# *******************************************************************************
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# (1) Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# (2) Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# (3) Neither the name of the copyright holder nor the names of any contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission from the respective party.
#
# (4) Other than as required in clauses (1) and (2), distributions in any form
# of modifications or other derivative works may not use the "OpenStudio"
# trademark, "OS", "os", or any other confusingly similar designation without
# specific prior written permission from Alliance for Sustainable Energy, LLC.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# *******************************************************************************

require 'pathname'

module EnergyPlus
  class StatFile
    attr_accessor :path
    attr_accessor :valid
    attr_accessor :lat
    attr_accessor :lon
    attr_accessor :elevation
    attr_accessor :gmt
    attr_accessor :monthlyDB
    attr_accessor :hdd18
    attr_accessor :cdd18
    attr_accessor :hdd10
    attr_accessor :cdd10

    def initialize(path)
      @path = Pathname.new(path)
      @valid = false
      @lat = []
      @lon = []
      @gmt = []
      @elevation = []
      @hdd18 = []
      @cdd18 = []
      @hdd10 = []
      @cdd10 = []
      @monthly_dry_bulb = []
      @delta_dry_bulb = []
      init
    end

    def valid?
      return @valid
    end

    # the mean of the mean monthly dry bulbs
    def mean_dry_bulb
      if !@monthly_dry_bulb.empty?
        sum = 0
        @monthly_dry_bulb.each { |db| sum += db }
        mean = sum / @monthly_dry_bulb.size
      else
        mean = ''
      end

      mean.to_f
    end

    # max - min of the mean monthly dry bulbs
    def delta_dry_bulb
      if !@monthly_dry_bulb.empty?
        delta_t = @monthly_dry_bulb.max - @monthly_dry_bulb.min
      else
        delta_t = ''
      end

      delta_t.to_f
    end

    private

    # initialize
    def init
      if @path.exist?
        File.open(@path) do |f|
          text = f.read.force_encoding('iso-8859-1')
          parse(text)
        end
      end
    end

    def parse(text)
      # get lat, lon, gmt
      regex = /\{(N|S)\s*([0-9]*).\s*([0-9]*)'\}\s*\{(E|W)\s*([0-9]*).\s*([0-9]*)'\}\s*\{GMT\s*(.*)\s*Hours\}/
      match_data = text.match(regex)
      if match_data.nil?
        puts "Can't find lat/lon/gmt"
        return
      else

        @lat = match_data[2].to_f + match_data[3].to_f / 60.0
        if match_data[1] == 'S'
          @lat = -@lat
        end

        @lon = match_data[5].to_f + match_data[6].to_f / 60.0
        if match_data[4] == 'W'
          @lon = -@lon
        end

        @gmt = match_data[7]
      end

      # get elevation
      regex = /Elevation --\s*(.*)m (above|below) sea level/
      match_data = text.match(regex)
      if match_data.nil?
        puts "Can't find elevation"
        return
      else
        @elevation = match_data[1].to_f
        if match_data[2] == 'below'
          @elevation = -@elevation
        end
      end

      # get heating and cooling degree days
      cdd10Regex = /-\s*(.*) annual.*cooling degree-days \(10.C baseline\)/
      match_data = text.match(cdd10Regex)
      if match_data.nil?
        puts "Can't find CDD 10"
        return
      else
        @cdd10 = match_data[1].to_f
      end

      hdd10Regex = /-\s*(.*) annual.*heating degree-days \(10.C baseline\)/
      match_data = text.match(hdd10Regex)
      if match_data.nil?
        puts "Can't find HDD 10"
        return
      else
        @hdd10 = match_data[1].to_f
      end

      cdd18Regex = /-\s*(.*) annual.*cooling degree-days \(18.*C baseline\)/
      match_data = text.match(cdd18Regex)
      if match_data.nil?
        puts "Can't find CDD 18"
        return
      else
        @cdd18 = match_data[1].to_f
      end

      hdd18Regex = /-\s*(.*) annual.*heating degree-days \(18.*C baseline\)/
      match_data = text.match(hdd18Regex)
      if match_data.nil?
        puts "Can't find HDD 18"
        return
      else
        @hdd18 = match_data[1].to_f
      end

      # use regex to get the temperatures
      regex = /Daily Avg(.*)\n/
      match_data = text.match(regex)
      if match_data.nil?
        puts "Can't find outdoor air temps"
        return
      else
        # first match is outdoor air temps
        monthly_temps = match_data[1].strip.split(/\s+/)

        # have to be 12 months
        if monthly_temps.size != 12
          puts "Can't find outdoor air temps"
          return
        end

        # insert as numbers
        monthly_temps.each { |temp| @monthly_dry_bulb << temp.to_f }
      end

      # now we are valid
      @valid = true
    end
  end
end