using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using edu.jhu.Cas.Jobs;
using edu.jhu.Cas.Util;

namespace edu.jhu.Cas.Service {
    /*
     * cleans up orphaned jobs.
     */
    public class JobCleanThread : CJobsDBThread {
        public override string ServiceName {
            get {
                return "Job Cleanup Service";
            }
        }
        public override string ServiceDescription {
            get {
                return "Sets status of orphaned jobs to failed.";
            }
        }
        public override int DefaultPanicMinutes {
            get {
                return (CYCLE_DELAY_SECONDS / 60) * 2;//twice the default cycle
            }
        }
        const string MAID_QUERY = @"
update jobs
set [status] = 4, [message] = 'Job failed', timeend = getdate()
where jobid in (
	select jobid from
	(
	  select name --all quick queue names
	  from servers s1, (
		--quick queues
		select target, min(queue) as queue from servers
		group by target
	  ) tmp
	  where tmp.queue = s1.queue and tmp.target = s1.target
	) qq, jobs j
	where
	 ([status] = 0 or [status] = 1 or [status] = 2) and --non final states
	qq.name = j.hostip --jobs in quick queues
	and datediff(mi, timesubmit, getdate()) > 60 --jobs not yet finished, over an hour
)
update jobs
set [status] = 2 --cancelling
where jobid in (
    select j.jobid
    from servers s2, jobs j
    where s2.name not in ( -- non quick queues
              select name from (--names of quick queues
		    --quick queues
		    select target, min(queue) as queue from servers
		    group by target
	      ) tmp, servers s1
	      where tmp.queue = s1.queue and tmp.target = s1.target
    )
    and j.[status] = 1 -- running
    and j.hostip = s2.name -- in a non-quick queue
    and datediff(mi, j.timestart, getdate()) > (s2.queue + 60) --an hour past their timeout
)
";
        const int CYCLE_DELAY_SECONDS = 1800;//every half hour
        SqlCommand mCom = new SqlCommand();

        public JobCleanThread()
            : base() {
            base.con.Open();
            mCom.Connection = base.con;
            mCom.CommandText = MAID_QUERY;
            mCom.Prepare();//then compile this query
        }
        protected override void Run() {
            for (; ; ) {
                try {
                    if (State == CJobsDBState.RUNNING) {
                        mCom.ExecuteNonQuery();
                        Console.WriteLine("JobCleanThread completed successfully");
                    }
                } catch (Exception e) {
                    CJobsService.Log(e.ToString(), System.Diagnostics.EventLogEntryType.Error);
                }
                try {
                    CycleComplete();
                } catch { }
                Thread.Sleep(CYCLE_DELAY_SECONDS * 1000);

            }
        }
        protected override void Halt() { }
    }
}