# Extend the class
class OpenStudio::Model::Model
  
  def run_simulation_and_log_errors(run_dir = "#{Dir.pwd}/Run")
    
    # Make the directory if it doesn't exist
    if !Dir.exists?(run_dir)
      Dir.mkdir(run_dir)
    end
    
    # Save the model to energyplus idf
    idf_name = 'in.idf'
    osm_name = 'in.osm'
    OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', "Starting simulation here: #{run_dir}.")
    forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
    idf = forward_translator.translateModel(self)
    idf_path = OpenStudio::Path.new("#{run_dir}/#{idf_name}")  
    osm_path = OpenStudio::Path.new("#{run_dir}/#{osm_name}")
    idf.save(idf_path,true)
    self.save(osm_path,true)
    
    # Set up the simulation
    # Find the weather file
    epw_path = self.get_full_weather_file_path
    if epw_path.empty?
      return false
    end
    epw_path = epw_path.get
    
    # If running on a regular desktop, use RunManager.
    # If running on OpenStudio Server, use WorkFlowMananger
    # to avoid slowdown from the run.   
    use_runmanager = true
    
    begin
      require 'openstudio-workflow'
      use_runmanager = false
    rescue LoadError
      use_runmanager = true
    end

    sql_path = nil
    if use_runmanager
      OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Running with RunManager.')

      # Find EnergyPlus
      ep_dir = OpenStudio.getEnergyPlusDirectory
      ep_path = OpenStudio.getEnergyPlusExecutable
      ep_tool = OpenStudio::Runmanager::ToolInfo.new(ep_path)
      idd_path = OpenStudio::Path.new(ep_dir.to_s + "/Energy+.idd")
      output_path = OpenStudio::Path.new("#{run_dir}/")
      
      # Make a run manager and queue up the run
      run_manager_db_path = OpenStudio::Path.new("#{run_dir}/run.db")
      # HACK: workaround for Mac with Qt 5.4, need to address in the future.
      OpenStudio::Application::instance().application(false)
      run_manager = OpenStudio::Runmanager::RunManager.new(run_manager_db_path, true, false, false, false)
      job = OpenStudio::Runmanager::JobFactory::createEnergyPlusJob(ep_tool,
                                                                   idd_path,
                                                                   idf_path,
                                                                   epw_path,
                                                                   output_path)
      
      run_manager.enqueue(job, true)

      # Start the run and wait for it to finish.
      while run_manager.workPending
        sleep 1
        OpenStudio::Application::instance.processEvents
      end
        
      sql_path = OpenStudio::Path.new("#{run_dir}/EnergyPlus/eplusout.sql")
      
      OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished run.')
      
    else # Use the openstudio-workflow gem
      OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Running with openstudio-workflow gem.')
      
      # Copy the weather file to this directory
      FileUtils.copy(epw_path.to_s, run_dir)

      # Run the simulation
      sim = OpenStudio::Workflow.run_energyplus('Local', run_dir)
      final_state = sim.run

      if final_state == :finished
        OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished run.')
      end
    
      sql_path = OpenStudio::Path.new("#{run_dir}/run/eplusout.sql")
    
    end
    
    # TODO Delete the eplustbl.htm and other files created
    # by the run for cleanliness.
    
    if OpenStudio::exists(sql_path)
      sql = OpenStudio::SqlFile.new(sql_path)
      # Check to make sure the sql file is readable,
      # which won't be true if EnergyPlus crashed during simulation.
      if !sql.connectionOpen
        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "The run failed, cannot create model.  Look at the eplusout.err file in #{File.dirname(sql_path.to_s)} to see the cause.")
        return false
      end
      # Attach the sql file from the run to the model
      self.setSqlFile(sql)
    else 
      OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "Results for the run couldn't be found here: #{sql_path}.")
      return false
    end
    
    # Report severe errors in the run
    error_query = "SELECT ErrorMessage 
        FROM Errors 
        WHERE ErrorType in(1,2)"
    errs = self.sqlFile.get.execAndReturnVectorOfString(error_query)
    if errs.is_initialized
      errs = errs.get
    end

    # Check that the run completed
    completed_query = "SELECT Completed FROM Simulations"
    completed = self.sqlFile.get.execAndReturnFirstDouble(completed_query)
    if completed.is_initialized
      completed = completed.get
      if completed == 0
        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "The run did not finish and had following errors: #{errs.join('\n')}")
        return false
      end
    end    
    
    # Check that the run completed with no severe errors
    completed_successfully_query = "SELECT CompletedSuccessfully FROM Simulations"
    completed_successfully = self.sqlFile.get.execAndReturnFirstDouble(completed_successfully_query)
    if completed_successfully.is_initialized
      completed_successfully = completed_successfully.get
      if completed_successfully == 0
        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "The run failed with the following severe or fatal errors: #{errs.join('\n')}")
        return false
      end
    end    
    
    # Log any severe errors that did not cause simulation to fail
    if errs.size > 0
      OpenStudio::logFree(OpenStudio::Warn, 'openstudio.model.Model', "The run completed but had the following severe errors: #{errs.join('\n')}")
    end

    return true

  end
  
end