require 'csv'
require 'fileutils'
require 'rubygems'
require 'json'
require 'yaml'

require 'spout/helpers/subject_loader'
require 'spout/helpers/chart_types'

module Spout
  module Commands
    class Graphs
      def initialize(variables, standard_version)
        @standard_version = standard_version

        spout_config = YAML.load_file('.spout.yml')

        @visit = ''

        if spout_config.kind_of?(Hash)
          @visit = spout_config['visit'].to_s.strip

          chart_variables = if spout_config['charts'].kind_of?(Array)
            spout_config['charts'].select{|c| c.kind_of?(Hash)}
          else
            []
          end
        else
          puts "The YAML file needs to be in the following format:"
          puts "---\nvisit: visit_variable_name\ncharts:\n- chart: age_variable_name\n  title: Age\n- chart: gender_variable_name\n  title: Gender\n- chart: race_variable_name\n  title: Race\n"
          exit
        end

        if Spout::Helpers::ChartTypes::get_json(@visit, 'variable') == nil
          if @visit == ''
            puts "The visit variable in .spout.yml can't be blank."
          else
            puts "Could not find the following visit variable: #{@visit}"
          end
          exit
        end
        missing_variables = chart_variables.select{|c| Spout::Helpers::ChartTypes::get_json(c['chart'], 'variable') == nil}
        if missing_variables.count > 0
          puts "Could not find the following chart variable#{'s' unless missing_variables.size == 1}: #{missing_variables.join(', ')}"
          exit
        end

        argv_string = variables.join(',')
        @number_of_rows = nil

        if match_data = argv_string.match(/-rows=(\d*)/)
          @number_of_rows = match_data[1].to_i
          argv_string.gsub!(match_data[0], '')
        end

        @valid_ids = argv_string.split(',').compact.reject{|s| s == ''}

        @chart_variables = chart_variables.unshift( { "chart" => @visit, "title" => 'Histogram' } )

        @variable_files = Dir.glob('variables/**/*.json')

        t = Time.now
        FileUtils.mkpath "graphs/#{@standard_version}"

        @subject_loader = Spout::Helpers::SubjectLoader.new(@variable_files, @valid_ids, @standard_version, @number_of_rows, @visit)

        @subject_loader.load_subjects_from_csvs!
        @subjects = @subject_loader.subjects
        compute_tables_and_charts

        puts "Took #{Time.now - t} seconds."
      end

      def compute_tables_and_charts
        variable_files_count = @variable_files.count
        @variable_files.each_with_index do |variable_file, file_index|
          json = JSON.parse(File.read(variable_file)) rescue json = nil
          next unless json
          next unless @valid_ids.include?(json["id"].to_s.downcase) or @valid_ids.size == 0
          next unless ["numeric", "integer", "choices"].include?(json["type"])
          variable_name  = json['id'].to_s.downcase
          next unless Spout::Models::Subject.method_defined?(variable_name)

          puts "#{file_index+1} of #{variable_files_count}: #{variable_file.gsub(/(^variables\/|\.json$)/, '').gsub('/', ' / ')}"


          stats = {
            charts: {},
            tables: {}
          }

          @chart_variables.each do |chart_type_hash|
            chart_type = chart_type_hash["chart"]
            chart_title = chart_type_hash["title"].downcase

            if chart_type == @visit
              filtered_subjects = @subjects.select{ |s| s.send(chart_type) != nil }  # and s.send(variable_name) != nil
              if filtered_subjects.count > 0
                stats[:charts][chart_title] = Spout::Helpers::ChartTypes::chart_histogram(chart_type, filtered_subjects, json, variable_name)
                stats[:tables][chart_title] = Spout::Helpers::ChartTypes::table_arbitrary(chart_type, filtered_subjects, json, variable_name)
              end
            else
              filtered_subjects = @subjects.select{ |s| s.send(chart_type) != nil } # and s.send(variable_name) != nil
              if filtered_subjects.count > 0
                stats[:charts][chart_title] = Spout::Helpers::ChartTypes::chart_arbitrary(chart_type, filtered_subjects, json, variable_name, visits)
                stats[:tables][chart_title] = visits.collect do |visit_display_name, visit_value|
                  visit_subjects = filtered_subjects.select{ |s| s._visit == visit_value }
                  unknown_subjects = visit_subjects.select{ |s| s.send(variable_name) == nil }
                  (visit_subjects.count > 0 && visit_subjects.count != unknown_subjects.count) ? Spout::Helpers::ChartTypes::table_arbitrary(chart_type, visit_subjects, json, variable_name, visit_display_name) : nil
                end.compact
              end
            end
          end

          chart_json_file = File.join('graphs', @standard_version, "#{json['id']}.json")
          File.open(chart_json_file, 'w') { |file| file.write( JSON.pretty_generate(stats) + "\n" ) }

        end
      end

      # [["Visit 1", "1"], ["Visit 2", "2"], ["CVD Outcomes", "3"]]
      def visits
        @visits ||= begin
          Spout::Helpers::ChartTypes::domain_array(@visit)
        end
      end

    end
  end
end