text:
#include <stdio.h>
#include <stdlib.h>
#include <vicNl.h>
#include <math.h>

static char vcid[] = "$Id$";

int  full_energy(int                  gridcell,
                 int                  rec,
                 atmos_data_struct   *atmos,
                 all_vars_struct     *all_vars,
                 dmy_struct          *dmy,
                 global_param_struct *gp,
		 lake_con_struct     *lake_con,
                 soil_con_struct     *soil_con,
                 veg_con_struct      *veg_con,
                 veg_hist_struct    **veg_hist)
/**********************************************************************
	full_energy	Keith Cherkauer		January 8, 1997

  This subroutine controls the model core, it solves both the energy
  and water balance models, as well as frozen soils.

  modifications:
  07-98 restructured to fix problems with distributed precipitation,
        and to add the ability to solve the snow model at different
	elevation bands within a single grid cell.                 KAC
  01-19-00 modified to work with the new atmosphere data structure
           implemented when the radiation forcing routines were
	   updated.  Also modified to use the new simplified
	   soil moisture storage for the frozen soil algorithm.    KAC
  12-01-00 modified to include the lakes and wetlands algorithm.   KAC
  11-18-02 Modified to handle blowing snow.  Also added debugging
           output for lake model.                                  LCB
  05-27-03 Updated passing of veg_con parameters for blowing snow
           to surface_fluxes.  Original did not account for the fact
           that veg_con is not allocated for veg = Nveg (bare soil)
           case.  This eliminates a memory error.                  KAC
  28-Sep-04 Added aero_resist_used to store the aerodynamic resistance
	    used in flux calculations.				TJB
  2006-Sep-23 Implemented flexible output configuration; now computation
	      of soil wetness and root zone soil moisture happens here.		TJB
  2006-Nov-07 Removed LAKE_MODEL option.					TJB
  2007-Apr-04 Modified to handle grid cell errors by returning to the
	      main subroutine, rather than ending the simulation.		GCT/KAC
  2007-May-01 Added case of SPATIAL_FROST = TRUE in modifications
	      from 2006-Sep-23.							GCT
  2007-Aug-10 Added features for EXCESS_ICE option.
	      Including calculating subsidence for each layer and
	      updating soil depth, effective porosity,
	      bulk density, and soil moisture and fluxes by calling
	      runoff function if subsidence occurs.				JCA
  2007-Sep-07 No longer resets ice content to previous time-step ice content if
	      subsidence has occurred.						JCA
  2007-Sep-19 Added MAX_SUBSIDENCE parameter to EXCESS_ICE option.		JCA
  2007-Sep-19 Fixed bug in subsidence calculation.				JCA
  2007-Nov-06 Added veg_con to parameter list of lakemain().  Replaced
	      lake.fraci with lake.areai.					LCB via TJB
  2008-Jan-23 Changed ice0 from a scalar to an array.  Previously,
	      when options.SNOW_BAND > 1, the value of ice0 computed
	      for earlier bands was always overwritten by the value
	      of ice0 computed for the final band (even if the final
	      band had 0 area).							JS via TJB
  2008-May-05 Changed moist from a scalar to an array (moist0).  Previously,
	      when options.SNOW_BAND > 1, the value of moist computed
	      for earlier bands was always overwritten by the value
	      of moist computed for the final band (even if the final
	      band had 0 area).							KAC via TJB
  2009-Jan-16 Modified aero_resist_used and Ra_used to become arrays of
	      two elements (surface and overstory); added
	      options.AERO_RESIST_CANSNOW.					TJB
  2009-May-17 Added asat to cell_data.						TJB
  2009-Jun-09 Modified to use extension of veg_lib structure to contain
	      bare soil information.						TJB
  2009-Jun-09 Modified to compute aero_resist for all potential evap
	      landcover types.							TJB
  2009-Jun-09 Cell_data structure now only stores final aero_resist
	      values (called "aero_resist").  Preliminary uncorrected
	      aerodynamic resistances for current vegetation and various
	      reference land cover types for use in potential evap
	      calculations is stored in temporary array aero_resist.		TJB
  2009-Jun-26 Simplified argument list of runoff() by passing all cell_data
	      variables via a single reference to the cell data structure.	TJB
  2009-Jul-22 Fixed error in assignment of cell.aero_resist.			TJB
  2009-Jul-31 Wetland portion of lake/wetland tile is now processed in
	      full_energy() instead of wetland_energy().  Lake funcions are
	      now called directly from full_energy instead of lakemain().	TJB
  2009-Sep-28 Moved lake_snow and lake_energy into lake_var structure.
	      Removed calls to initialize_prcp and update_prcp.			TJB
  2009-Sep-30 Miscellaneous fixes for lake model.				TJB
  2009-Oct-05 Miscellaneous fixes for lake model, including updating/
	      rescaling of lake and wetland storages and fluxes to account
	      for changes in lake area.						TJB
  2009-Nov-09 Changed definition of lake->sarea to include ice extent; other
	      changes to handle case when lake fraction goes to 0.		LCB via TJB
  2010-Mar-31 Added runoff_in.							TJB
  2010-Sep-24 Changed atmos.runoff_in to atmos.channel_in.  Added
	      lake_var.channel_in to store it.					TJB
  2010-Nov-02 Changed units of lake_var moisture fluxes to volume (m3).		TJB
  2010-Nov-26 Changed argument list of water_balance().				TJB
  2011-May-31 Prepare_full_energy() is now always called.			TJB
  2011-Jun-03 Added options.ORGANIC_FRACT.  Soil properties now take
	      organic fraction into account.					TJB
  2012-Jan-01 Modified condition for determining whether to simulate lakes
	      to check whether lake_idx >= 0.					TJB
  2012-Jan-16 Removed LINK_DEBUG code						BN
  2012-Aug-28 Added accumulation of rain and snow over lake to grid cell
	      totals.								TJB
  2013-Jul-25 Added photosynthesis terms.					TJB
  2013-Jul-25 Added soil carbon terms.						TJB
  2013-Dec-26 Removed EXCESS_ICE option.					TJB
  2013-Dec-27 Removed (unused) SPATIAL_FROST code.				TJB
  2014-Mar-28 Removed DIST_PRCP option.						TJB
  2014-Apr-25 Added non-climatological veg params.				TJB
  2014-Apr-25 Added partial vegcover fraction.					TJB

**********************************************************************/
{
  extern veg_lib_struct *veg_lib;
  extern option_struct   options;
  char                   overstory;
  int                    i, j, p;
  int                    lidx;
  int                    iveg;
  int                    Nveg;
  int                    veg_class;
  int                    band;
  int                    Nbands;
  int                    ErrorFlag;
  double                 out_prec[2*MAX_BANDS];
  double                 out_rain[2*MAX_BANDS];
  double                 out_snow[2*MAX_BANDS];
  double                 out_short=0;
  double                 dp;
  double                 ice0[MAX_BANDS];
  double                 moist0[MAX_BANDS];
  double                 surf_atten;
  double                 Tend_surf;
  double                 Tend_grnd;
  double                 wind_h;
  double                 height;
  double                 displacement[3];
  double                 roughness[3];
  double                 ref_height[3];
  double               **aero_resist;
  double                 Cv;
  double                 Le;
  double                 Melt[2*MAX_BANDS];
  double                 bare_albedo;
  double                 snow_inflow[MAX_BANDS];
  double                 rainonly;
  double                 sum_runoff;
  double                 sum_baseflow;
  double                 tmp_wind[3];
  double                 gauge_correction[2];
  float 	         lag_one;
  float 	         sigma_slope;
  float  	         fetch;
  int                    pet_veg_class;
  double                 lakefrac;
  double                 fraci;
  double                 wetland_runoff;
  double                 wetland_baseflow;
  double                 oldsnow;
  double                 snowprec;
  double                 rainprec;
  int                    cidx;
  lake_var_struct       *lake_var;
  cell_data_struct     **cell;
  veg_var_struct       **veg_var;
  energy_bal_struct    **energy;
  snow_data_struct     **snow;

  /* Allocate aero_resist array */
  aero_resist = (double**)calloc(N_PET_TYPES+1,sizeof(double*));
  for (p=0; p<N_PET_TYPES+1; p++) {
    aero_resist[p] = (double*)calloc(3,sizeof(double));
  }

  /* set local pointers */
  cell    = all_vars->cell;
  energy  = all_vars->energy;
  lake_var = &all_vars->lake_var;
  snow    = all_vars->snow;
  veg_var = all_vars->veg_var;

  Nbands = options.SNOW_BAND;

  /* Set number of vegetation types */
  Nveg      = veg_con[0].vegetat_type_num;

  /** Set Damping Depth **/
  dp        = soil_con->dp;

  /* Compute gauge undercatch correction factors
     - this assumes that the gauge is free of vegetation effects, so gauge
     correction is constant for the entire grid cell */
  if( options.CORRPREC && atmos->prec[NR] > 0 )
    correct_precip(gauge_correction, atmos->wind[NR], gp->wind_h,
		   soil_con->rough, soil_con->snow_rough);
  else {
    gauge_correction[0] = 1;
    gauge_correction[1] = 1;
  }
  atmos->out_prec = 0;
  atmos->out_rain = 0;
  atmos->out_snow = 0;

  /* Assign current veg albedo and LAI */
  if (rec >= 0) {
    // Loop over vegetated tiles
    for(iveg = 0; iveg < Nveg; iveg++){
      veg_class = veg_con[iveg].veg_class;
      if (veg_hist[rec][iveg].vegcover[0] < MIN_VEGCOVER)
        veg_hist[rec][iveg].vegcover[0] = MIN_VEGCOVER;
      for ( band = 0; band < Nbands; band++ ) {
        veg_var[iveg][band].vegcover = veg_hist[rec][iveg].vegcover[0];
        veg_var[iveg][band].albedo = veg_hist[rec][iveg].albedo[0];
        veg_var[iveg][band].LAI = veg_hist[rec][iveg].LAI[0];
        // Convert LAI from global to local
        veg_var[iveg][band].LAI /= veg_var[iveg][band].vegcover;
        veg_var[iveg][band].Wdew /= veg_var[iveg][band].vegcover;
        veg_var[iveg][band].Wdmax = veg_var[iveg][band].LAI*LAI_WATER_FACTOR;
        snow[iveg][band].snow_canopy /= veg_var[iveg][band].vegcover;
      }
    }
  }

  /**************************************************
    Solve Energy and/or Water Balance for Each
    Vegetation Type
  **************************************************/
  for(iveg = 0; iveg <= Nveg; iveg++){

    /** Solve Veg Type only if Coverage Greater than 0% **/
    if (veg_con[iveg].Cv > 0.0) {
      Cv = veg_con[iveg].Cv;
      Nbands = options.SNOW_BAND;

      /** Lake-specific processing **/
      if (veg_con[iveg].LAKE) {

        /* Update areai to equal new ice area from previous time step. */
        lake_var->areai = lake_var->new_ice_area;

        /* Compute lake fraction and ice-covered fraction */
        if (lake_var->areai < 0) lake_var->areai = 0;
	if (lake_var->sarea > 0) {
	  fraci = lake_var->areai/lake_var->sarea;
	  if(fraci > 1.0) fraci = 1.0;
	}
	else
	  fraci = 0.0;
	lakefrac = lake_var->sarea/lake_con->basin[0];

        Nbands = 1;
        Cv *= (1-lakefrac);

        if (Cv == 0)
          continue;

      }

      /**************************************************
        Initialize Model Parameters
      **************************************************/

      for(band = 0; band < Nbands; band++) {
	if(soil_con->AreaFract[band] > 0) {

	  /* Initialize energy balance variables */
	  energy[iveg][band].shortwave = 0;
	  energy[iveg][band].longwave  = 0.;

	  /* Initialize snow variables */
	  snow[iveg][band].vapor_flux        = 0.;
	  snow[iveg][band].canopy_vapor_flux = 0.;
	  snow_inflow[band]                  = 0.;
	  Melt[band*2]                       = 0.;

	}
      }

      /* Initialize precipitation storage */
      for ( j = 0; j < 2*MAX_BANDS; j++ ) {
        out_prec[j] = 0;
        out_rain[j] = 0;
        out_snow[j] = 0;
      }

      /** Define vegetation class number **/
      veg_class = veg_con[iveg].veg_class;

      /** Initialize other veg vars **/
      if (iveg < Nveg) {
	for(band=0; band<Nbands; band++) {
          veg_var[iveg][band].rc = HUGE_RESIST;
        }
      }

      /** Assign wind_h **/
      /** Note: this is ignored below **/
      wind_h = veg_lib[veg_class].wind_h;

      /** Compute Surface Attenuation due to Vegetation Coverage **/
      surf_atten = (1-veg_var[iveg][0].vegcover)*1.0
                   + veg_var[iveg][0].vegcover
                   * exp(-veg_lib[veg_class].rad_atten * veg_var[iveg][0].LAI);

      /* Initialize soil thermal properties for the top two layers */
      prepare_full_energy(iveg, Nveg, options.Nnode, all_vars, soil_con, moist0, ice0);

      /** Compute Bare (free of snow) Albedo **/
      if (iveg!=Nveg){
        bare_albedo = veg_var[iveg][0].albedo;
      }
      else {
        bare_albedo = BARE_SOIL_ALBEDO;
      }

      /*************************************
	Compute the aerodynamic resistance
	for current veg cover and various
	types of potential evap
      *************************************/

      /* Loop over types of potential evap, plus current veg */
      /* Current veg will be last */
      for (p=0; p<N_PET_TYPES+1; p++) {

        /* Initialize wind speeds */
        tmp_wind[0] = atmos->wind[NR];
        tmp_wind[1] = -999.;
        tmp_wind[2] = -999.;

        /* Set surface descriptive variables */
        if (p < N_PET_TYPES_NON_NAT) {
	  pet_veg_class = veg_lib[0].NVegLibTypes+p;
        }
        else {
	  pet_veg_class = veg_class;
        }
        displacement[0] = veg_lib[pet_veg_class].displacement[dmy[rec].month-1];
        roughness[0]    = veg_lib[pet_veg_class].roughness[dmy[rec].month-1];
        overstory       = veg_lib[pet_veg_class].overstory;
	if (p >= N_PET_TYPES_NON_NAT)
          if ( roughness[0] == 0 ) roughness[0] = soil_con->rough;

        /* Estimate vegetation height */
        height = calc_veg_height(displacement[0]);

        /* Estimate reference height */
        if(displacement[0] < wind_h)
          ref_height[0] = wind_h;
        else
          ref_height[0] = displacement[0] + wind_h + roughness[0];

        /* Compute aerodynamic resistance over various surface types */
        /* Do this not only for current veg but also all types of PET */
        ErrorFlag = CalcAerodynamic(overstory, height,
		        veg_lib[pet_veg_class].trunk_ratio,
                        soil_con->snow_rough, soil_con->rough,
		        veg_lib[pet_veg_class].wind_atten,
			aero_resist[p], tmp_wind,
		        displacement, ref_height,
		        roughness);
        if ( ErrorFlag == ERROR ) return ( ERROR );

      }

      /* Initialize final aerodynamic resistance values */
      for ( band = 0; band < Nbands; band++ ) {
        if( soil_con->AreaFract[band] > 0 ) {
          cell[iveg][band].aero_resist[0] = aero_resist[N_PET_TYPES][0];
          cell[iveg][band].aero_resist[1] = aero_resist[N_PET_TYPES][1];
        }
      }

      /******************************
        Compute nitrogen scaling factors and initialize other veg vars
      ******************************/
      if (options.CARBON && iveg < Nveg) {
	for(band=0; band<Nbands; band++) {
          for (cidx=0; cidx<options.Ncanopy; cidx++) {
            veg_var[iveg][band].rsLayer[cidx] = HUGE_RESIST;
          }
          veg_var[iveg][band].aPAR = 0;
          if (dmy->hour == 0) {
            calc_Nscale_factors(veg_lib[veg_class].NscaleFlag,
                                veg_con[iveg].CanopLayerBnd,
                                veg_lib[veg_class].LAI[dmy[rec].month-1],
                                soil_con->lat,
                                soil_con->lng,
                                soil_con->time_zone_lng,
                                dmy[rec],
                                veg_var[iveg][band].NscaleFactor);
          }
          if (dmy[rec].month == 1 && dmy[rec].day == 1) {
            veg_var[iveg][band].AnnualNPPPrev = veg_var[iveg][band].AnnualNPP;
            veg_var[iveg][band].AnnualNPP = 0;
          }
        }
      }

      /******************************
        Solve ground surface fluxes
      ******************************/

      for ( band = 0; band < Nbands; band++ ) {
	if( soil_con->AreaFract[band] > 0 ) {

	  lag_one     = veg_con[iveg].lag_one;
	  sigma_slope = veg_con[iveg].sigma_slope;
	  fetch       = veg_con[iveg].fetch;

	  /* Initialize pot_evap */
	  for (p=0; p<N_PET_TYPES; p++)
	    cell[iveg][band].pot_evap[p] = 0;

	  ErrorFlag = surface_fluxes(overstory, bare_albedo, height, ice0[band], moist0[band],
				     surf_atten, &(Melt[band*2]), &Le,
				     aero_resist,
				     displacement, gauge_correction,
				     &out_prec[band*2],
				     &out_rain[band*2], &out_snow[band*2],
				     ref_height, roughness,
				     &snow_inflow[band],
				     tmp_wind, veg_con[iveg].root, Nbands,
				     options.Nlayer, Nveg, band, dp, iveg, rec, veg_class,
				     atmos, dmy, &(energy[iveg][band]), gp,
				     &(cell[iveg][band]),
				     &(snow[iveg][band]),
				     soil_con, &(veg_var[iveg][band]),
				     lag_one, sigma_slope, fetch, veg_con[iveg].CanopLayerBnd);

	  if ( ErrorFlag == ERROR ) return ( ERROR );

	  atmos->out_prec += out_prec[band*2] * Cv * soil_con->AreaFract[band];
	  atmos->out_rain += out_rain[band*2] * Cv * soil_con->AreaFract[band];
	  atmos->out_snow += out_snow[band*2] * Cv * soil_con->AreaFract[band];

          /********************************************************
            Compute soil wetness and root zone soil moisture
          ********************************************************/
          cell[iveg][band].rootmoist = 0;
          cell[iveg][band].wetness = 0;
          for(lidx=0;lidx<options.Nlayer;lidx++) {
            if (veg_con->root[lidx] > 0) {
              cell[iveg][band].rootmoist += cell[iveg][band].layer[lidx].moist;
            }
	    cell[iveg][band].wetness += (cell[iveg][band].layer[lidx].moist - soil_con->Wpwp[lidx])/(soil_con->porosity[lidx]*soil_con->depth[lidx]*1000 - soil_con->Wpwp[lidx]);
          }
          cell[iveg][band].wetness /= options.Nlayer;

	} /** End non-zero area band **/
      } /** End Loop Through Elevation Bands **/

    } /** end non-zero area veg tile **/
  } /** end of vegetation loop **/

  /* Convert LAI back to global */
  if (rec >= 0) {
    for(iveg = 0; iveg < Nveg; iveg++){
      for ( band = 0; band < Nbands; band++ ) {
        veg_var[iveg][band].LAI *= veg_var[iveg][band].vegcover;
        veg_var[iveg][band].Wdmax *= veg_var[iveg][band].vegcover;
      }
    }
  }

  for (p=0; p<N_PET_TYPES+1; p++) {
    free((char *)aero_resist[p]);
  }
  free((char *)aero_resist);

  /****************************
     Run Lake Model
  ****************************/

  /** Compute total runoff and baseflow for all vegetation types
      within each snowband. **/
  if ( options.LAKES && lake_con->lake_idx >= 0 ) {

    wetland_runoff = wetland_baseflow = 0;
    sum_runoff = sum_baseflow = 0;

    // Loop through all vegetation tiles
    for ( iveg = 0; iveg <= Nveg; iveg++ ) {

      /** Solve Veg Tile only if Coverage Greater than 0% **/
      if (veg_con[iveg].Cv  > 0.) {

	Cv = veg_con[iveg].Cv;
        Nbands = options.SNOW_BAND;
        if (veg_con[iveg].LAKE) {
          Cv *= (1-lakefrac);
          Nbands = 1;
        }

        // Loop through snow elevation bands
        for ( band = 0; band < Nbands; band++ ) {
          if ( soil_con->AreaFract[band] > 0 ) {

            if (veg_con[iveg].LAKE) {
              wetland_runoff += ( cell[iveg][band].runoff
                          * Cv * soil_con->AreaFract[band] );
              wetland_baseflow += ( cell[iveg][band].baseflow
                          * Cv * soil_con->AreaFract[band] );
              cell[iveg][band].runoff = 0;
              cell[iveg][band].baseflow = 0;
            }
            else {
              sum_runoff += ( cell[iveg][band].runoff
                            * Cv * soil_con->AreaFract[band] );
              sum_baseflow += ( cell[iveg][band].baseflow
                              * Cv * soil_con->AreaFract[band] );
              cell[iveg][band].runoff *= (1-lake_con->rpercent);
              cell[iveg][band].baseflow *= (1-lake_con->rpercent);
            }

	  }
        }
      }
    }

    /** Run lake model **/
    iveg = lake_con->lake_idx;
    band = 0;
    lake_var->runoff_in   = (sum_runoff * lake_con->rpercent + wetland_runoff)*soil_con->cell_area*0.001; // m3
    lake_var->baseflow_in = (sum_baseflow * lake_con->rpercent + wetland_baseflow)*soil_con->cell_area*0.001; // m3
    lake_var->channel_in  = atmos->channel_in[NR]*soil_con->cell_area*0.001; // m3
    lake_var->prec        = atmos->prec[NR]*lake_var->sarea*0.001; // m3
    rainonly = calc_rainonly(atmos->air_temp[NR], atmos->prec[NR],
			     gp->MAX_SNOW_TEMP, gp->MIN_RAIN_TEMP);
    if ( (int)rainonly == ERROR ) {
      return( ERROR );
    }

    /**********************************************************************
       Solve the energy budget for the lake.
     **********************************************************************/

    oldsnow = lake_var->snow.swq;
    snowprec = gauge_correction[SNOW] * (atmos->prec[NR] - rainonly);
    rainprec = gauge_correction[SNOW] * rainonly;
    atmos->out_prec += (snowprec + rainprec) * lake_con->Cl[0] * lakefrac;
    atmos->out_rain += rainprec * lake_con->Cl[0] * lakefrac;
    atmos->out_snow += snowprec * lake_con->Cl[0] * lakefrac;

    ErrorFlag = solve_lake(snowprec, rainprec, atmos->air_temp[NR],
                           atmos->wind[NR], atmos->vp[NR] / 1000.,
                           atmos->shortwave[NR], atmos->longwave[NR],
                           atmos->vpd[NR] / 1000.,
                           atmos->pressure[NR] / 1000.,
                           atmos->density[NR], lake_var, *lake_con,
                           *soil_con, gp->dt, rec, gp->wind_h, dmy[rec], fraci);
    if ( ErrorFlag == ERROR ) return (ERROR);

    /**********************************************************************
       Solve the water budget for the lake.
     **********************************************************************/

    ErrorFlag = water_balance(lake_var, *lake_con, gp->dt, all_vars, rec, iveg, band, lakefrac, *soil_con, *veg_con);
    if ( ErrorFlag == ERROR ) return (ERROR);

  } // end if (options.LAKES && lake_con->lake_idx >= 0)

  return (0);
}


text:
/* Base16 Atelier Cave Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */

/* Atelier-Cave Comment */
.hljs-comment {
  color: #7e7887;
}

/* Atelier-Cave Red */
.hljs-variable,
.hljs-attribute,
.hljs-tag,
.hljs-regexp,
.hljs-name,
.ruby .hljs-constant,
.xml .hljs-tag .hljs-title,
.xml .hljs-pi,
.xml .hljs-doctype,
.html .hljs-doctype,
.css .hljs-id,
.css .hljs-class,
.css .hljs-pseudo {
  color: #be4678;
}

/* Atelier-Cave Orange */
.hljs-number,
.hljs-preprocessor,
.hljs-built_in,
.hljs-literal,
.hljs-params,
.hljs-constant {
  color: #aa573c;
}

/* Atelier-Cave Yellow */
.ruby .hljs-class .hljs-title,
.css .hljs-rule .hljs-attribute {
  color: #a06e3b;
}

/* Atelier-Cave Green */
.hljs-string,
.hljs-value,
.hljs-inheritance,
.hljs-header,
.ruby .hljs-symbol,
.xml .hljs-cdata {
  color: #2a9292;
}

/* Atelier-Cave Aqua */
.hljs-title,
.css .hljs-hexcolor {
  color: #398bc6;
}

/* Atelier-Cave Blue */
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
  color: #576ddb;
}

/* Atelier-Cave Purple */
.hljs-keyword,
.javascript .hljs-function {
  color: #955ae7;
}

.diff .hljs-deletion,
.diff .hljs-addition {
  color: #19171c;
  display: inline-block;
  width: 100%;
}
.diff .hljs-deletion {
  background-color: #be4678;
}
.diff .hljs-addition {
  background-color: #2a9292;
}
.diff .hljs-change {
  color: #576ddb;
}

.hljs {
  display: block;
  overflow-x: auto;
  background: #19171c;
  color: #8b8792;
  padding: 0.5em;
  -webkit-text-size-adjust: none;
}

.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
  opacity: 0.5;
}

redpajama_set_name: RedPajamaGithub


text:
package org.zaproxy.addon.network.internal.client.apachev5;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import java.net.PasswordAuthentication;
import java.util.Locale;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.NTCredentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.zaproxy.addon.network.ConnectionOptions;
import org.zaproxy.addon.network.internal.client.HttpProxy;

/** Unit test for  {@link ProxyCredentialsProvider}. */
class ProxyCredentialsProviderUnitTest {

    private static final HttpProxy HTTP_PROXY =
            new HttpProxy(
                    "proxy.example.org",
                    443,
                    "Realm",
                    new PasswordAuthentication("UserName", "Password".toCharArray()));

    private ConnectionOptions connectionOptions;
    private ProxyCredentialsProvider proxyCredentialsProvider;

    @BeforeEach
    void setUp() {
        connectionOptions = mock(ConnectionOptions.class);
        given(connectionOptions.getHttpProxy()).willReturn(HTTP_PROXY);
        given(connectionOptions.isHttpProxyEnabled()).willReturn(true);
        given(connectionOptions.isHttpProxyAuthEnabled()).willReturn(true);
        proxyCredentialsProvider = new ProxyCredentialsProvider(connectionOptions);
    }

    @ParameterizedTest
    @ValueSource(strings = {"basic", "Basic", "digest", "Digest"})
    void shouldProvideUsernamePasswordCredentialsForBasicAndDigestSchemes(String scheme) {
        // Given
        AuthScope authScope = createProxyAuthScope(scheme);
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(instanceOf(UsernamePasswordCredentials.class)));
        UsernamePasswordCredentials credentials = (UsernamePasswordCredentials) providedCredentials;
        assertThat(
                credentials.getUserName(),
                is(equalTo(HTTP_PROXY.getPasswordAuthentication().getUserName())));
        assertThat(
                credentials.getPassword(),
                is(equalTo(HTTP_PROXY.getPasswordAuthentication().getPassword())));
    }

    @Test
    void shouldProvideNtCredentialsForOtherSchemes() {
        // Given
        AuthScope authScope = createProxyAuthScope("ntlm");
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(instanceOf(NTCredentials.class)));
        NTCredentials credentials = (NTCredentials) providedCredentials;
        assertThat(
                credentials.getUserName(),
                is(equalTo(HTTP_PROXY.getPasswordAuthentication().getUserName())));
        assertThat(
                credentials.getPassword(),
                is(equalTo(HTTP_PROXY.getPasswordAuthentication().getPassword())));
        assertThat(credentials.getWorkstation(), is(equalTo("")));
        assertThat(
                credentials.getDomain(),
                is(equalTo(HTTP_PROXY.getRealm().toUpperCase(Locale.ROOT))));
    }

    @Test
    void shouldNotProvideCredentialsIfProxyNotEnabled() {
        // Given
        AuthScope authScope = createProxyAuthScope("basic");
        given(connectionOptions.isHttpProxyEnabled()).willReturn(false);
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(nullValue()));
    }

    @Test
    void shouldNotProvideCredentialsIfProxyAuthNotEnabled() {
        // Given
        AuthScope authScope = createProxyAuthScope("basic");
        given(connectionOptions.isHttpProxyAuthEnabled()).willReturn(false);
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(nullValue()));
    }

    @Test
    void shouldNotProvideCredentialsIfHostDoesNotMatch() {
        // Given
        AuthScope authScope =
                createAuthScope("basic", "Other Host", HTTP_PROXY.getPort(), HTTP_PROXY.getRealm());
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(nullValue()));
    }

    @Test
    void shouldNotProvideCredentialsIfPortDoesNotMatch() {
        // Given
        AuthScope authScope =
                createAuthScope(
                        "basic",
                        HTTP_PROXY.getHost(),
                        HTTP_PROXY.getPort() + 1,
                        HTTP_PROXY.getRealm());
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(nullValue()));
    }

    @Test
    void shouldNotProvideCredentialsIfRealmDoesNotMatch() {
        // Given
        AuthScope authScope =
                createAuthScope("basic", HTTP_PROXY.getHost(), HTTP_PROXY.getPort(), "Other Realm");
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(nullValue()));
    }

    @Test
    void shouldProvideCredentialsIfAnyRealmMatch() {
        // Given
        HttpProxy httpProxy =
                new HttpProxy(
                        "proxy.example.org",
                        443,
                        "",
                        new PasswordAuthentication("UserName", "Password".toCharArray()));
        given(connectionOptions.getHttpProxy()).willReturn(httpProxy);
        AuthScope authScope =
                createAuthScope(
                        "basic",
                        httpProxy.getHost(),
                        httpProxy.getPort(),
                        "Other Realm But Any Allowed");
        // When
        Credentials providedCredentials = proxyCredentialsProvider.getCredentials(authScope, null);
        // Then
        assertThat(providedCredentials, is(notNullValue()));
    }

    private static AuthScope createProxyAuthScope(String scheme) {
        return createAuthScope(
                scheme, HTTP_PROXY.getHost(), HTTP_PROXY.getPort(), HTTP_PROXY.getRealm());
    }

    private static AuthScope createAuthScope(String scheme, String host, int port, String realm) {
        return new AuthScope(null, host, port, realm, scheme);
    }
}


text:
<?php

namespace ReverseAuction\ReverseAuctionBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class RegistrationControllerTest extends WebTestCase
{
    public function testRegistration()
    {
        $client = static::createClient();

        $crawler = $client->request('GET', '/Registration');
    }

}


text:
/**
 *
 * Wait for an element (selected by css selector) for the provided amount of
 * milliseconds to have a value. If multiple elements get queryied by given
 * selector, it returns true (or false if reverse flag is set) if at least one
 * element has a value.
 *
 * <example>
    :index.html
    <input name="someInput" id="elem" value=""></input>
    <script type="text/javascript">
        setTimeout(function () {
            document.getElementById('elem').value = 'some text';
        }, 2000);
    </script>

    :waitForTextExample.js
    it('should detect when element has value', function () {
        browser.waitForValue('#elem', 3000);

        // same as
        elem = $('#elem');
        elem.waitForValue(3000)
    });
 * </example>
 *
 * @alias browser.waitForValue
 * @param {String}   selector element to wait
 * @param {Number=}  ms       time in ms (default: 500)
 * @param {Boolean=} reverse  if true it waits for the opposite (default: false)
 * @uses utility/waitUntil, property/getValue
 * @type utility
 *
 */

import { WaitUntilTimeoutError, isTimeoutError } from '../utils/ErrorHandler'

let waitForValue = function (selector, ms, reverse) {
    /**
     * we can't use default values for function parameter here because this would
     * break the ability to chain the command with an element if reverse is used, like
     *
     * ```js
     * var elem = $('#elem');
     * elem.waitForXXX(10000, true);
     * ```
     */
    reverse = typeof reverse === 'boolean' ? reverse : false

    /*!
     * ensure that ms is set properly
     */
    if (typeof ms !== 'number') {
        ms = this.options.waitforTimeout
    }

    return this.waitUntil(() => {
        return this.getValue(selector).then((value) => {
            if (!Array.isArray(value)) {
                return (value !== '') !== reverse
            }

            let result = reverse
            for (let val of value) {
                if (!reverse) {
                    result = result || val !== ''
                } else {
                    result = result && val === ''
                }
            }

            return result !== reverse
        })
    }, ms).catch((e) => {
        selector = selector || this.lastResult.selector

        if (isTimeoutError(e)) {
            let isReversed = reverse ? 'with' : 'without'
            throw new WaitUntilTimeoutError(`element (${selector}) still ${isReversed} a value after ${ms}ms`)
        }
        throw e
    })
}

export default waitForValue


text:
'use strict';

const models = require('./index');

/**
 * @class
 * Initializes a new instance of the ResourceGroupExportResult class.
 * @constructor
 * @member {object} [template] The template content.
 *
 * @member {object} [error] The error.
 *
 * @member {string} [error.code] The error code returned when exporting the
 * template.
 *
 * @member {string} [error.message] The error message describing the export
 * error.
 *
 * @member {string} [error.target] The target of the error.
 *
 * @member {array} [error.details] Validation error.
 *
 */
class ResourceGroupExportResult {
  constructor() {
  }

  /**
   * Defines the metadata of ResourceGroupExportResult
   *
   * @returns {object} metadata of ResourceGroupExportResult
   *
   */
  mapper() {
    return {
      required: false,
      serializedName: 'ResourceGroupExportResult',
      type: {
        name: 'Composite',
        className: 'ResourceGroupExportResult',
        modelProperties: {
          template: {
            required: false,
            serializedName: 'template',
            type: {
              name: 'Object'
            }
          },
          error: {
            required: false,
            serializedName: 'error',
            type: {
              name: 'Composite',
              className: 'ResourceManagementErrorWithDetails'
            }
          }
        }
      }
    };
  }
}

module.exports = ResourceGroupExportResult;


text: [SD-1643] Publish to sonatype


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using AutoMapper;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Reference.Commerce.Shared.AutomapperProfiles;
using EPiServer.Reference.Commerce.Site.Features.Global.Shared.Models;

namespace EPiServer.Reference.Commerce.Site.Infrastructure.Automapper
{
    [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
    public class AutomapperInitialize : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<ProductProfile>();
            });

        }

        public void Uninitialize(InitializationEngine context) { }
    }

}


text:
package com.github.bpark.vertx.webconsole;

import com.github.bpark.vertx.webconsole.handler.ClasspathContentHandler;
import com.github.bpark.vertx.webconsole.handler.DeployHandler;
import com.github.bpark.vertx.webconsole.handler.ListDeploymentsHandler;
import com.github.bpark.vertx.webconsole.handler.UndeployHandler;
import com.github.bpark.vertx.webconsole.handler.VersionHandler;
import org.vertx.java.busmods.BusModBase;
import org.vertx.java.core.http.HttpServer;
import org.vertx.java.core.http.RouteMatcher;

/**
 * @author bpark.
 */
public class WebConsoleVerticle extends BusModBase {

    private static final String ROUTE_VERSION = "/version";
    private static final String ROUTE_RESOURCES = "/resources";
    private static final String ROUTE_REMOVE = "/remove";
    private static final String ROUTE_DEPLOY = "/deploy";

    private static final String CONFIG_HOST = "host";
    private static final String DEFAULT_HOST = "localhost";

    private static final String CONFIG_PORT = "port";
    private static final int DEFAULT_PORT = 8990;

    @Override
    public void start() {
        super.start();

        InformationProvider informationProvider = new InformationProvider(this.container);

        HttpServer server = vertx.createHttpServer();
        RouteMatcher routeMatcher = new RouteMatcher();

        routeMatcher.get(ROUTE_VERSION, new VersionHandler());
        routeMatcher.get(ROUTE_RESOURCES, new ListDeploymentsHandler(informationProvider));
        routeMatcher.post(ROUTE_REMOVE, new UndeployHandler(informationProvider, container));
        routeMatcher.post(ROUTE_DEPLOY, new DeployHandler(informationProvider, container));
        routeMatcher.noMatch(new ClasspathContentHandler());

        server.requestHandler(routeMatcher);

        String host = getOptionalStringConfig(CONFIG_HOST, DEFAULT_HOST);
        int port = getOptionalIntConfig(CONFIG_PORT, DEFAULT_PORT);

        server.listen(port, host);
    }

}


text:
package de.uniol.inf.is.odysseus.trajectory.logicaloperator;

public class TrajectoryIdEnricherAO {

}


text:
package org.wildfly.security.manager.action;

import java.security.PrivilegedAction;

/**
 * A security action to create a thread.
 *
 * @author David M. Lloyd
 */
public final class CreateThreadAction implements PrivilegedAction<Thread> {

    private final ThreadGroup group;
    private final Runnable target;
    private final String name;
    private final long stackSize;

    /**
     * Construct a new instance.
     *
     * @param name the name of the thread (may not be {@code null})
     */
    public CreateThreadAction(final String name) {
        this(null, null, name, 0L);
    }

    /**
     * Construct a new instance.
     *
     * @param group the thread group to use
     * @param name the name of the thread (may not be {@code null})
     */
    public CreateThreadAction(final ThreadGroup group, final String name) {
        this(group, null, name, 0L);
    }

    /**
     * Construct a new instance.
     *
     * @param target the runnable target
     * @param name the name of the thread (may not be {@code null})
     */
    public CreateThreadAction(final Runnable target, final String name) {
        this(null, target, name, 0L);
    }

    /**
     * Construct a new instance.
     *
     * @param group the thread group to use
     * @param target the runnable target
     * @param name the name of the thread (may not be {@code null})
     */
    public CreateThreadAction(final ThreadGroup group, final Runnable target, final String name) {
        this(group, target, name, 0L);
    }

    /**
     * Construct a new instance.
     *
     * @param group the thread group to use
     * @param target the runnable target
     * @param name the name of the thread (may not be {@code null})
     * @param stackSize the stack size to use
     */
    public CreateThreadAction(final ThreadGroup group, final Runnable target, final String name, final long stackSize) {
        this.group = group;
        this.target = target;
        this.name = name;
        this.stackSize = stackSize;
    }

    public Thread run() {
        return new Thread(group, target, name, stackSize);
    }
}


text:
import {
  colors,
  rhythm
} from '../../lib/traits'

export default {
  tabs: {
    textAlign: 'center',
    '@media (min-width: 48em)': {
      textAlign: 'left'
    }
  },

  button: {
    paddingBottom: rhythm(0.25),
    marginRight: rhythm(0.5),
    marginBottom: rhythm(0.5),
    textTransform: 'uppercase',
    fontWeight: 'bold',
    borderBottom: '2px solid transparent'
  },

  activeButton: (theme) => ({
    color: colors.dark,
    borderBottomColor: colors.dark
  }),

  pagination: {
    textAlign: 'center'
  }
}


text:
<?php
	return [

		/*
		|--------------------------------------------------------------------------
		| Batched Migration settings
		|--------------------------------------------------------------------------
		|
		| You can define a few settings here which configure the way
		| migrations will be created.
		|
		*/

		/*
		|
		| The name of the migration may not contain certain words
		|
		 */
		'filter_name' => true,

		/**
		 * The words that are not allowed in the migration name
		 */
		'filtered'    => [

			'table',
			'schema'
		],

		/**
		 * The migration name must be prefixed
		 */
		'prefix_name' => true,

		/**
		 * The migration name prefixes
		 */
		'prefixes'    => [

			'create',
			'update'
		],

	];


text:
@interface PodsDummy_RoverCocoTest : NSObject
@end
@implementation PodsDummy_RoverCocoTest
@end


text:
<?php

import('lib.pkp.classes.scheduledTask.ScheduledTask');

class OpenAccessNotification extends ScheduledTask {

	/**
	 * Constructor.
	 */
	function OpenAccessNotification() {
		$this->ScheduledTask();
	}

	function sendNotification ($users, $journal, $issue) {
		if ($users->getCount() != 0) {

			import('lib.pkp.classes.mail.MailTemplate');
			$email = new MailTemplate('OPEN_ACCESS_NOTIFY', $journal->getPrimaryLocale());

			$email->setSubject($email->getSubject($journal->getPrimaryLocale()));
			$email->setReplyTo(null);
			$email->addRecipient($journal->getSetting('contactEmail'), $journal->getSetting('contactName'));

			$paramArray = array(
				'journalName' => $journal->getLocalizedName(),
				'journalUrl' => Request::url($journal->getPath()),
				'editorialContactSignature' => $journal->getSetting('contactName') . "\n" . $journal->getLocalizedName()
			);
			$email->assignParams($paramArray);

			$publishedArticleDao = DAORegistry::getDAO('PublishedArticleDAO');
			$publishedArticles = $publishedArticleDao->getPublishedArticlesInSections($issue->getId());
			$mimeBoundary = '==boundary_' . md5(microtime());

			$templateMgr = TemplateManager::getManager();
			$templateMgr->assign('body', $email->getBody($journal->getPrimaryLocale()));
			$templateMgr->assign('templateSignature', $journal->getSetting('emailSignature'));
			$templateMgr->assign('mimeBoundary', $mimeBoundary);
			$templateMgr->assign('issue', $issue);
			$templateMgr->assign('publishedArticles', $publishedArticles);

			$email->addHeader('MIME-Version', '1.0');
			$email->setContentType('multipart/alternative; boundary="'.$mimeBoundary.'"');
			$email->setBody($templateMgr->fetch('subscription/openAccessNotifyEmail.tpl'));

			while ($user = $users->next()) {
				$email->addBcc($user->getEmail(), $user->getFullName());
			}

			$email->send();
		}
	}

	function sendNotifications ($journal, $curDate) {

		// Only send notifications if subscriptions and open access notifications are enabled
		if ($journal->getSetting('publishingMode') == PUBLISHING_MODE_SUBSCRIPTION && $journal->getSetting('enableOpenAccessNotification')) {

			$curYear = $curDate['year'];
			$curMonth = $curDate['month'];
			$curDay = $curDate['day'];

			// Check if the current date corresponds to the open access date of any issues
			$issueDao = DAORegistry::getDAO('IssueDAO');
			$issues = $issueDao->getPublishedIssues($journal->getId());

			while ($issue = $issues->next()) {
				$accessStatus = $issue->getAccessStatus();
				$openAccessDate = $issue->getOpenAccessDate();

				if ($accessStatus == ISSUE_ACCESS_SUBSCRIPTION && !empty($openAccessDate) && strtotime($openAccessDate) == mktime(0,0,0,$curMonth, $curDay, $curYear)) {
					// Notify all users who have open access notification set for this journal
					$userSettingsDao = DAORegistry::getDAO('UserSettingsDAO');
					$users = $userSettingsDao->getUsersBySetting('openAccessNotification', true, 'bool', $journal->getId());
					$this->sendNotification($users, $journal, $issue);
				}
			}
		}
	}

	function execute() {
		$journalDao = DAORegistry::getDAO('JournalDAO');
		$journals = $journalDao->getAll(true);

		$todayDate = array(
			'year' => date('Y'),
			'month' => date('n'),
			'day' => date('j')
		);

		while ($journal = $journals->next()) {
			// Send notifications based on current date
			$this->sendNotifications($journal, $todayDate);
		}

		// If it is the first day of a month but previous month had only
		// 30 days then simulate 31st day for open access dates that end on
		// that day.
		$shortMonths = array(2,4,6,8,10,12);

		if (($todayDate['day'] == 1) && in_array(($todayDate['month'] - 1), $shortMonths)) {

			$curDate['day'] = 31;
			$curDate['month'] = $todayDate['month'] - 1;

			if ($curDate['month'] == 12) {
				$curDate['year'] = $todayDate['year'] - 1;
			} else {
				$curDate['year'] = $todayDate['year'];
			}

			$journals = $journalDao->getAll(true);
			while ($journal = $journals->next()) {
				// Send reminders for simulated 31st day of short month
				$this->sendNotifications($journal, $curDate);
			}
		}

		// If it is the first day of March, simulate 29th and 30th days for February
		// or just the 30th day in a leap year.
		if (($todayDate['day'] == 1) && ($todayDate['month'] == 3)) {

			$curDate['day'] = 30;
			$curDate['month'] = 2;
			$curDate['year'] = $todayDate['year'];

			$journals = $journalDao->getAll(true);
			while ($journal = $journals->next()) {
				// Send reminders for simulated 30th day of February
				$this->sendNotifications($journal, $curDate);
			}

			// Check if it's a leap year
			if (date("L", mktime(0,0,0,0,0,$curDate['year'])) != '1') {

				$curDate['day'] = 29;

				$journals = $journalDao->getAll(true);
				while ($journal = $journals->next()) {
					// Send reminders for simulated 29th day of February
					$this->sendNotifications($journal, $curDate);
				}
			}
		}
	}
}

?>


text:
import netlink
import cStringIO
import pdb
import pprint

def getaddr_inet():
    con = netlink.new_route()
    payload = netlink.route_getaddr(netlink.AF_INET, 0x12345)
    con.send(payload)
    msgs = []
    goout = False
    while True:
        d = con.recv(65533)
        b = cStringIO.StringIO(d)
        while True:
            if b.tell() >= len(d):
                break
            msg = netlink.parse_nlmsg(b)
            if msg["type"] == netlink.DONE:
                goout = True
                break
            elif msg["type"] == netlink.ERROR:
                raise ValueError(msg)
            mlen = b.tell() - 16 + msg["len"]
            payload = netlink.parse_ifaddr(b)
            attrs = netlink.parse_attrs(b, mlen)
            msgs.append({
                "msg": msg,
                "payload": payload,
                "attrs": attrs
                })
        if goout:
            break
    b.close()
    return msgs

pprint.pprint(getaddr_inet())


text:
package com.feicent.zhang.guava.eventbus;

import com.google.common.eventbus.Subscribe;

public class IntegerListener {
	private Integer lastMessage;

	@Subscribe
	public void listen(Integer integer) {
		lastMessage = integer;
		System.out.println("Message:" + lastMessage);
	}

	public Integer getLastMessage() {
		return lastMessage;
	}
}


text:
{{ item.name }}

{{ property.header }}:

{{ item[property.alias] }}

    <umb-empty-state
       ng-if="!content"
       position="center">
       <localize key="content_noItemsToShow">There are no items to show</localize>
    </umb-empty-state>


text:
namespace GitVersion;

public interface IVersionWriter
{
    void Write(Assembly assembly);
    void WriteTo(Assembly assembly, Action<string?> writeAction);
}


text:
package org.oauthsimple.http;

import org.oauthsimple.utils.HttpDate;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class Headers {
	private Date servedDate;
	private Date lastModified;
	private Date expires;
	private String cacheControl;
	private boolean noCache;
	private int maxAgeSeconds = -1;
	private int sMaxAgeSeconds = -1;
	private String etag;
	private int ageSeconds = -1;
	private String contentEncoding;
	private String transferEncoding;
	private int contentLength = -1;
	private String contentType;
	private List<String> rawCookies;
	private final Map<String, List<String>> rawHeaders;

	public Headers(Map<String, List<String>> rawHeaders) {
		this.rawHeaders = rawHeaders;

		for (String key : rawHeaders.keySet()) {
			String fieldName = key;
			String value = rawHeaders.get(key).get(0);
			if (CACHE_CONTROL.equalsIgnoreCase(fieldName)) {
				cacheControl = value;
			} else if (DATE.equalsIgnoreCase(fieldName)) {
				servedDate = HttpDate.parse(value);
			} else if (EXPIRES.equalsIgnoreCase(fieldName)) {
				expires = HttpDate.parse(value);
			} else if (LAST_MODIFIED.equalsIgnoreCase(fieldName)) {
				lastModified = HttpDate.parse(value);
			} else if (ETAG.equalsIgnoreCase(fieldName)) {
				etag = value;
			} else if (PRAGMA.equalsIgnoreCase(fieldName)) {
				if ("no-cache".equalsIgnoreCase(value)) {
					noCache = true;
				}
			} else if (SET_COOKIE.equals(fieldName)) {
				rawCookies = rawHeaders.get(fieldName);
			} else if ("Age".equalsIgnoreCase(fieldName)) {
				ageSeconds = parseSeconds(value);
			} else if (CONTENT_TYPE.equalsIgnoreCase(fieldName)) {
				contentType = value;
			} else if (CONTENT_ENCODING.equalsIgnoreCase(fieldName)) {
				contentEncoding = value;
			} else if (TRANSFER_ENCODING.equalsIgnoreCase(fieldName)) {
				transferEncoding = value;
			} else if (CONTENT_LENGTH.equalsIgnoreCase(fieldName)) {
				contentLength = parseInt(value);
			}
		}
	}

	private static int parseInt(String value) {
		try {
			return Integer.parseInt(value);
		} catch (NumberFormatException ignored) {
			return 0;
		}
	}

	private static int parseSeconds(String value) {
		try {
			long seconds = Long.parseLong(value);
			if (seconds > Integer.MAX_VALUE) {
				return Integer.MAX_VALUE;
			} else if (seconds < 0) {
				return 0;
			} else {
				return (int) seconds;
			}
		} catch (NumberFormatException e) {
			return -1;
		}
	}

	public Date getServedDate() {
		return servedDate;
	}

	public Date getLastModified() {
		return lastModified;
	}

	public Date getExpires() {
		return expires;
	}

	public String getCacheControl() {
		return cacheControl;
	}

	public boolean isNoCache() {
		return noCache;
	}

	public int getMaxAgeSeconds() {
		return maxAgeSeconds;
	}

	public int getsMaxAgeSeconds() {
		return sMaxAgeSeconds;
	}

	public String getEtag() {
		return etag;
	}

	public void setEtag(String etag) {
		this.etag = etag;
	}

	public int getAgeSeconds() {
		return ageSeconds;
	}

	public String getContentEncoding() {
		return contentEncoding;
	}

	public String getTransferEncoding() {
		return transferEncoding;
	}

	public int getContentLength() {
		return contentLength;
	}

	public String getContentType() {
		return contentType;
	}

	public List<String> getRawCookies() {
		return rawCookies;
	}

	public int size() {
		return rawHeaders.size();
	}

	public String getHeader(String filedName) {
		List<String> headers = rawHeaders.get(filedName);
		if (headers == null || headers.isEmpty()) {
			return null;
		}
		return rawHeaders.get(filedName).get(0);
	}

	public int getHeaderInt(String filedName, int defaultValue) {
		List<String> headers = rawHeaders.get(filedName);
		if (headers == null || headers.isEmpty()) {
			return defaultValue;
		}
		String value = rawHeaders.get(filedName).get(0);
		try {
			return Integer.valueOf(value);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	public static final String ACCEPT = "Accept";
	public static final String ACCEPT_CHARSET = "Accept-Charset";
	public static final String ACCEPT_ENCODING = "Accept-Encoding";
	public static final String ACCEPT_LANGUAGE = "Accept-Language";
	public static final String AUTHORIZATION = "Authorization";
	public static final String CACHE_CONTROL = "Cache-Control";
	public static final String CONTENT_ENCODING = "Content-Encoding";
	public static final String CONTENT_LANGUAGE = "Content-Language";
	public static final String CONTENT_LENGTH = "Content-Length";
	public static final String CONTENT_LOCATION = "Content-Location";
	public static final String CONTENT_TYPE = "Content-Type";
	public static final String DATE = "Date";
	public static final String ETAG = "ETag";
	public static final String EXPIRES = "Expires";
	public static final String HOST = "Host";
	public static final String IF_MATCH = "If-Match";
	public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
	public static final String IF_NONE_MATCH = "If-None-Match";
	public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
	public static final String LAST_MODIFIED = "Last-Modified";
	public static final String LOCATION = "Location";
	public static final String PRAGMA = "Pragma";
	public static final String TRANSFER_ENCODING = "Transfer-Encoding";
	public static final String USER_AGENT = "User-Agent";
	public static final String VARY = "Vary";
	public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
	public static final String COOKIE = "Cookie";
	public static final String SET_COOKIE = "Set-Cookie";
}