# encoding: UTF-8
require 'process_manager/master'
require 'instance_metadata'
require 'instance_agent/plugins/codedeploy/deployment_command_tracker'

module InstanceAgent
  module Runner
    class DeploymentAlreadyInProgressException < Exception;  end 
    
    class Master < ProcessManager::Daemon::Master
            
      def self.description(pid = $$)
        "master #{pid}"
      end

      def self.child_class
        ::InstanceAgent::Runner::Child
      end

      def self.pid_description
        ProcessManager::Config.config[:program_name]
      end

      def self.log_file
        File.join(ProcessManager::Config.config[:log_dir], "#{ProcessManager::Config.config[:program_name]}.log")
      end

      def self.pid_file
        File.join(ProcessManager::Config.config[:pid_dir], "#{ProcessManager::Config.config[:program_name]}.pid")
      end

      # Stops the master after recieving the kill signal
      # is overriden from ProcessManager::Daemon::Master
      def stop
        if (pid = self.class.find_pid)
          puts "Checking first if a deployment is already in progress"
          ProcessManager::Log.info("Checking first if any deployment lifecycle event is in progress #{description(pid)}")
          begin
            if(InstanceAgent::Plugins::CodeDeployPlugin::DeploymentCommandTracker.check_deployment_event_inprogress?)
              ProcessManager::Log.info("Master process (#{pid}) will not be shut down right now, as a deployment is already in progress")
              raise "A deployment is already in Progress",DeploymentAlreadyInProgressException
            else
              puts "Stopping #{description(pid)}"
              ProcessManager::Log.info("Stopping #{description(pid)}")
            end  
            Process.kill('TERM', pid)
          rescue Errno::ESRCH
          end
          
          begin
            Timeout.timeout(ProcessManager::Config.config[:kill_agent_max_wait_time_seconds]) do  
              loop do
                begin
                  Process.kill(0, pid)
                  sleep(1)
                rescue Errno::ESRCH
                  break
                end
              end
            end
          rescue Timeout::Error
            puts "Child processes still running. Master going down."
            ProcessManager::Log.warn("Master process (#{pid}) going down before terminating child")
          end
        else
          puts "Nothing running that could be stopped"
        end
      end

      def kill_children(sig)
        children.each do |index, child_pid|
          begin
            Process.kill(sig, child_pid)
          rescue Errno::ESRCH
          end
        end
    
        begin
          Timeout.timeout(ProcessManager::Config.config[:kill_agent_max_wait_time_seconds]) do
            children.each do |index, child_pid|
              begin
                Process.wait(child_pid)
              rescue Errno::ESRCH
              end
            end
          end
        rescue Timeout::Error
          children.each do |index, child_pid|
            if ProcessManager.process_running?(child_pid)
              pid = self.class.find_pid
              puts "Stopping #{ProcessManager::Config.config[:program_name]} agent(#{pid}) but child(#{child_pid}) still processing."
              ProcessManager::Log.warn("Stopping #{ProcessManager::Config.config[:program_name]} agent(#{pid}) but child(#{child_pid}) is still processing.")
            end
          end
        end

      end
      
    end
  end
end
