content: package me.aikin.refactoring.longer;
  
  import java.util.Date;
  
  public class ResidentialSite {
      private Zone zone;
      private Reading[] readings = new Reading[1000];
      private static final double TAX_RATE = 0.05;
  
      public ResidentialSite(Zone zone) {
          this.zone = zone;
      }
  
      public void addReading(Reading newReading) {
          // add reading to end of array
          int i = 0;
          while (readings[i] != null) i++;
          readings[i] = newReading;
      }
  
      public Dollars charge() {
          // find last reading
          int i = 0;
          while (readings[i] != null) i++;
          int usage = readings[i - 1].getAmount() - readings[i - 2].getAmount();
          Date end = readings[i - 1].getDate();
          Date start = readings[i - 2].getDate();
          start.setDate(start.getDate() + 1); //set to begining of period
          return charge(usage, start, end);
      }
  
      private Dollars charge(int usage, Date start, Date end) {
          Dollars result;
          double summerFraction;
  
          // Find out how much of period is in the summer
          if (start.after(zone.getSummerEnd()) || end.before(zone.getSummerStart()))
              summerFraction = 0;
          else if (!start.before(zone.getSummerStart()) && !start.after(zone.getSummerEnd()) && !end.before(zone.getSummerStart()) && !end.after(zone.getSummerEnd())) {
              summerFraction = 1;
          } else {
              // part in summer part in winter
              double summerDays;
              if (start.before(zone.getSummerStart()) || start.after(zone.getSummerEnd())) {
                  // end is in the summer
                  summerDays = DayOfYear(end) - DayOfYear(zone.getSummerStart()) + 1;
              } else {
                  // start is in summer
                  summerDays = DayOfYear(zone.getSummerEnd()) - DayOfYear(start) + 1;
              }
              summerFraction = summerDays / (DayOfYear(end) - DayOfYear(start) + 1);
          }
  
          result = new Dollars((usage * zone.getSummerRate() * summerFraction) + (usage * zone.getWinterRate() * (1 - summerFraction)));
          result = result.plus(new Dollars(result.times(TAX_RATE)));
  
          Dollars fuel = new Dollars(usage * 0.0175);
          result = result.plus(fuel);
  
          result = new Dollars(result.plus(fuel.times(TAX_RATE)));
  
          return result;
  
      }
  
      private int DayOfYear(Date arg) {
          int result;
          switch (arg.getMonth()) {
              case 0:
                  result = 0;
                  break;
              case 1:
                  result = 31;
                  break;
              case 2:
                  result = 59;
                  break;
              case 3:
                  result = 90;
                  break;
              case 4:
                  result = 120;
                  break;
              case 5:
                  result = 151;
                  break;
              case 6:
                  result = 181;
                  break;
              case 7:
                  result = 212;
                  break;
              case 8:
                  result = 243;
                  break;
              case 9:
                  result = 273;
                  break;
              case 10:
                  result = 304;
                  break;
              case 11:
                  result = 334;
                  break;
              default:
                  throw new IllegalArgumentException();
          }
          result += arg.getDate();
  
          //check leap year
          if ((arg.getYear() % 4 == 0) && ((arg.getYear() % 100 != 0) ||
                  ((arg.getYear() + 1900) % 400 == 0))) {
              result++;
          }
  
          return result;
      }
  }
  