using System;
using edu.jhu.Cas.Util;
using System.Data;
using edu.jhu.Cas.Users;
using System.Web.Services;
/**
 * This is the administrative web service interface for casjobs. It contains many usefull routines for use inside the system to discover if a given user has correct privileges, to comlete cacelation of jobs. Nominally users will not need to use this interface unless they are developing a comlete alternative interface to Casjobs.
  $Id: CasJobsAdmin.asmx.cs 111295 2010-05-12 02:49:19Z nli $
  $Revision: 111295 $
  $Date: 2010-05-11 22:49:19 -0400 (Tue, 11 May 2010) $
  */
namespace edu.jhu.Cas.Jobs {
    // for jabva compatability it is important to have http:// in the namespace.
    [WebService(Namespace = "http://Jobs.Cas.jhu.edu", Name = "CasJobsAdmin", Description = "All of these methods require you to be a job's owner or admin.  Most of these events are already handled internally; should not need to call.")]
    public class CasJobsAdmin : System.Web.Services.WebService {
        public const string VERSION = "$Name$ $Revision: 111295 $";
        private long serviceId = ID.SERVICE_ID;
        public long CreateJob(long wsid, string qry, string modifiedQry,
            string target, string taskname, int estimate,
            int autoComplete) {
            return CasJobs.CreateJob(wsid, qry, modifiedQry, target, taskname, estimate,
                autoComplete);
        }

        [WebMethod(Description = "This will mark a job as started")]
        public void StartJob(long wsid, long jobid, string hosted, string table) {
            IsOwnerOrAdmin(wsid, jobid);
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsid);
            job.addTimeStarted(DateTime.Now);
            job.addJobId(jobid);
            job.SetValue(JobAdmin.HOST_IP, hosted);
            job.SetValue(JobAdmin.STATUS, QUERY_STATUS.STARTED);
            SqlFactory.insert(job, JobAdmin.StartJobStatement);
        }
        [WebMethod(Description = "This will mark a job as failed.")]
        public void FailJob(long wsid, long jobid, string message, string table) {
            IsOwnerOrAdmin(wsid, jobid);
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsid);
            job.addJobId(jobid);
            job.SetValue(JobAdmin.MESSAGE, message);
            job.SetValue(JobAdmin.STATUS, QUERY_STATUS.FAILED);
            job.addTimeEnd(DateTime.Now);
            SqlFactory.insert(job, JobAdmin.FailJobStatement);
            if ((message.IndexOf("already an object") > -1 && message.IndexOf(table) > -1)) {
                (new TableJobs()).RollBackTable(wsid, jobid, table);
            }
            if (IsInLowestQueue(wsid, jobid) == null) {
                Mailer.MaybeMail(wsid, "\tQuery job #" + jobid.ToString() + " failed with this error: "
                    + message, QUERY_STATUS.FAILED, jobid);
            }
        }
        [WebMethod(Description = "set status to finished, update message, rows, and sets TimeEnd")]
        public void FinishedJob(long wsid, long jobid, string message,
            long rows, string table) {
            IsOwnerOrAdmin(wsid, jobid);
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsid);
            job.addJobId(jobid);
            job.SetValue(JobAdmin.MESSAGE, message);
            job.SetValue(JobAdmin.STATUS, QUERY_STATUS.FINISHED);
            job.addTimeEnd(DateTime.Now);
            job.addRows(rows);
            SqlFactory.insert(job, JobAdmin.FinishedJobStatement);
            if (table != null)
                (new TableJobs()).AssignTable(wsid, jobid, table);
            if (IsInLowestQueue(wsid, jobid) == null) {
                Mailer.MaybeMail(wsid, "\tJob #" + jobid.ToString() + " has completed!"
                    + message, QUERY_STATUS.FINISHED, jobid);
            }
        }
        [WebMethod(Description = "status to finished, update message, rows, output location, and sets TimeEnd")]
        public void FinishedOutputJob(long wsid, long jobid, string message, string outLoc,
            long rows) {
            IsOwnerOrAdmin(wsid, jobid);
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsid);
            job.SetValue(JobAdmin.OUTPUT_LOC, outLoc);
            job.addJobId(jobid);
            job.SetValue(JobAdmin.MESSAGE, message);
            job.SetValue(JobAdmin.STATUS, QUERY_STATUS.FINISHED);
            job.addTimeEnd(DateTime.Now);
            job.addRows(rows);
            SqlFactory.insert(job, JobAdmin.FinishedOutputJobStatement);
            Mailer.MaybeMail(wsid, "\tExtraction job #" + jobid.ToString() + " finished : "
                + message, QUERY_STATUS.FINISHED, jobid);
        }
        [WebMethod(Description = "Same as public, but unrestricted by wsId.  User must have admin priv.")]
        public DataSet FindJobDataSet(long wsId, string predicate) {
            (new CasUsers()).HasPrivilege(wsId, "admin");
            JobAdmin job = new JobAdmin();
            //wsId is currently ignored
            string qry = JobAdmin.FindJobAdminStatement;
            if (predicate.Length > 1)
                qry += " where ";
            qry += predicate;
            DataSet dataSet = SqlFactory.select(job, qry);
            return dataSet;
        }
        [WebMethod(Description = "Same as public, but unrestricted by wsId.  User must have admin priv.")]
        public Job[] FindJob(long wsId, string predicate) {
            DataSet ds = FindJobDataSet(wsId, predicate);
            Job[] jobs = DataConverter.dataSet2Job(ds);
            return jobs;
        }
        [WebMethod(Description = "If job is finished, failed or some kind of cancelled, submits a new job with old parameters and a new jobid.  Updates estimate.  Returns -1 if just is not complete.", MessageName = "ResubmitJob")]
        public long ResubmitJob(long wsId, long jobid, int estimate) {
            IsOwnerOrAdmin(wsId, jobid);
            CasJobs cj = new CasJobs();
            if (cj.StatusJob(wsId, jobid) > 1) {
                Job j = FindJob(wsId, " jobid = " + jobid +
                    " and webservicesid = " + wsId)[0];
                j.ModifiedQuery = (new FilterFactory()).EnforceMyDb(j);
                return CreateJob(wsId, j.Query, j.ModifiedQuery,
                    j.Target, j.TaskName, estimate, j.AutoComplete);
            }
            return -1;
        }
        [WebMethod(Description = "If job is finished, failed or some kind of cancelled, submits a new job with old parameters and a new jobid.  Bumps job to next queue.  Returns -1 if job is not bumped.", MessageName = "ResubmitAndBumpJob")]
        public long ResubmitJob(long wsId, long jobid) {
            IsOwnerOrAdmin(wsId, jobid);
            CasJobs cj = new CasJobs();
            Job[] jobs = FindJob(serviceId, " jobid = " + jobid +
                " and webservicesid = " + wsId);
            Job j = jobs[0];
            //must always enforce mydb.   Any query job resubmission will always be going to a longer (not shortest) queue.
            //and any job that is not a query is never resubmitted.  
            j.ModifiedQuery = (new FilterFactory()).EnforceMyDb(j);
            (new CasUsers()).CreateMyDB(wsId);
            JobAdmin qJob = new JobAdmin();
            qJob.SetValue(JobAdmin.TARGET, j.Target);
            qJob.SetValue(JobAdmin.ESTIMATE, j.Estimate);
            Object o = SqlFactory.scalar(qJob, JobAdmin.FindNextQueueStatement);
            int estimate = int.Parse(o.ToString()); ;
            return CreateJob(wsId, j.Query, j.ModifiedQuery,
                j.Target, j.TaskName, estimate, j.AutoComplete);
        }
        [WebMethod(Description = "Resubmits the id's last job with same taskname.  Updates estimate. Returns -1 on error.")]
        /**
         * no checks on this yet
         */
        public long ResubmitTask(long wsId, string taskname, int estimate) {
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsId);
            job.SetValue(JobAdmin.TASK_NAME, taskname);
            Object o = SqlFactory.scalar(job, JobAdmin.ResubmitTaskStatement);
            if (o != null) {
                string s = o.ToString();
                if (s.Length > 0) {
                    long jobid = long.Parse(s);
                    return ResubmitJob(wsId, jobid, estimate);
                }
            }
            return -1;
        }
        [WebMethod(Description = "Updates a job")]
        public void UpdateJob(long wsid, long jobid, string setThis) {
            (new CasUsers()).HasPrivilege(wsid, "admin");
            JobAdmin job = new JobAdmin();
            SqlFactory.insert(job, "update jobs set " + setThis + " where jobid = " + jobid);
        }
        [WebMethod(Description = "Returns appropriate connection string if true, null if not")]
        public Server IsInLowestQueue(int estimate, string target) {
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.TARGET, target);
            job.SetValue(JobAdmin.ESTIMATE, estimate);
            DataSet d = SqlFactory.select(
                job, JobAdmin.IsInLowestQueueStatement);
            Server s = new Server();
            foreach (DataTable table in d.Tables) {
                foreach (DataRow r in table.Rows) {
                    foreach (DataColumn c in table.Columns) {
                        string aa = c.ColumnName.ToLower();
                        switch (aa) {
                            case "name":
                                s.Name = r[c].ToString();
                                break;
                            case "queue":
                                s.Queue = int.Parse(r[c].ToString());
                                break;
                            case "host":
                                s.Host = r[c].ToString();
                                break;
                            case "usr":
                                s.User = r[c].ToString();
                                break;
                            case "cat":
                                s.Catalog = r[c].ToString();
                                break;
                            case "password":
                                s.Pass = r[c].ToString();
                                break;
                            case "cstringextra":
                                s.CStringExtra = r[c].ToString();
                                break;
                        }
                    }
                }
            }
            if (s.Name == null || s.Name.Length == 0) return null;
            return s;
        }
        public Server IsInLowestQueue(long wsid, long jobid) {
            CasJobs ca = new CasJobs();
            Job job = ca.FindJob(ID.SERVICE_ID, "jobid = " + jobid)[0];
            return IsInLowestQueue(job.Estimate, job.Target);
        }
        public void CompleteCancel(long wsid, long jobid, string message, string table) {
            IsOwnerOrAdmin(wsid, jobid);
            JobAdmin job = new JobAdmin();
            job.SetValue(JobAdmin.WEB_SERVICES_ID, wsid);
            job.addJobId(jobid);
            job.SetValue(JobAdmin.MESSAGE, message);
            job.SetValue(JobAdmin.STATUS, QUERY_STATUS.CANCELED);
            job.addTimeEnd(DateTime.Now);
            SqlFactory.insert(job, JobAdmin.FailJobStatement);
        }
        public void IsOwnerOrAdmin(long wsid, long jobid) {
            if (!IsOwner(wsid, jobid))
                (new CasUsers()).HasPrivilege(wsid, "admin");
        }
        public bool IsOwner(long wsid, long jobid) {
            Job[] jobs = FindJob(serviceId, "jobid = " + jobid);
            if (jobs.Length < 1) return false;
            return jobs[0].WebServicesID == wsid;
        }
    }
}
/**
 * $Log$
 * Revision 1.14  2008/03/27 20:40:16  nli
 * fixed an issue with sightless accounts and SYSTEM jobs
 *
 * Revision 1.13  2008/02/22 06:26:00  nli
 * *** empty log message ***
 *
 * Revision 1.12  2007/11/28 03:40:17  nli
 * jobsservice redo
 *
 * Revision 1.11  2007/05/08 20:50:54  nli
 * data-intensive operations in mydbcontext.aspx are now asyncronous
 *
 * Revision 1.10  2007/05/05 00:27:33  nli
 * --improved table to job tracking
 * --removed 'tables' table
 *
 * Revision 1.9  2007/04/25 18:51:05  nli
 * removed redundant information from servers and mydbhosts table
 * code modified to support this
 * schema changes:
 * servers ->
 *   --add CStringExtra column, varchar(200)
 *   --add Password column, varchar(200)
 *   --rename owner column to usr
 *   --fill in appropriate values
 *   --remove ConnectionString column
 *
 * mydbhosts ->
 *   -- rename 'user' to usr
 *   -- add CStringExtraColumn
 *   -- add admin_usr varchar column
 *   -- add admin_pw varchar column
 *
 * Revision 1.8  2007/04/25 17:03:27  nli
 * optimized sql generation in JobXXX classes
 *
 * Revision 1.7  2006/09/14 16:34:32  nli
 * minor cosmetic changes
 *
 * Revision 1.6  2005/10/31 18:44:20  nli
 * --HasIntoClause Regexes bit more robust
 *
 * Revision 1.5  2005/05/31 17:57:19  womullan
 *  Added some general comments. Fixed The Admin page resetting users password SPR6843. Added New Password box to admin page to allow admin to change users password.
 *
 * Revision 1.4  2005/01/19 22:02:24  womullan
 *  Mulitple bugs fixed - old failed jobs in output removed, better subjetc for email, eail for output nolonger says failed when it worked.
 *
 * Revision 1.3  2004/11/01 21:10:02  womullan
 *  Absolute Namespace :
 *
 * Revision 1.2  2004/06/09 20:47:13  womullan
 *  DDL allowed in special cases
 *
 * Revision 1.1.1.1  2004/04/27 16:38:29  cvsuser
 * import CasJobs to FERMI
 *
 * Revision 1.6  2004/04/05 19:21:52  womullan
 *  Never email on short jobs. User may opt in/out of group scheme on create account/change profile
 *
 * Revision 1.5  2004/04/02 20:39:09  nli
 * view jobs time bug fixed
 *
 * Revision 1.4  2004/03/15 17:04:54  nli
 * updated groups stuff, disabled autocomplete
 *
 * Revision 1.3  2004/03/12 21:15:32  nli
 * datareader, table link, etc
 *
 * Revision 1.2  2004/02/27 23:31:09  nli
 * job cancel fixed
 * lock level lowered
 *
 * Revision 1.1.1.1  2004/02/18 16:38:26  nli
 * new version
 *
 * Revision 1.3  2004/02/02 14:59:30  nli
 * don't mail sys jobs
 *
 * Revision 1.2  2004/01/27 19:28:05  nli
 * yup
 *
 * Revision 1.1.1.1  2004/01/25 18:16:57  nli
 * first
 *
 * Revision 1.1.1.1  2004/01/20 20:59:56  nli
 * new
 *
 * Revision 1.23  2003/11/26 22:06:41  womullan
 *  added name some places
 *
 * Revision 1.22  2003/10/29 19:19:03  nli
 * crap
 *
 * Revision 1.21  2003/10/29 19:09:39  nli
 * test
 *
 * Revision 1.20  2003/10/24 17:20:31  nli
 * some bugfixes in linked server parser
 *
 * Revision 1.19  2003/10/21 18:45:39  nli
 * bug in modifiedquery field
 *
 * Revision 1.18  2003/10/21 17:15:21  nli
 * cleanup
 *
 * Revision 1.17  2003/10/21 17:13:51  nli
 * virtualhost implemented, all targets are virtual
 *
 * Revision 1.16  2003/08/27 18:15:23  nli
 * debug
 *
 * Revision 1.15  2003/07/31 21:33:10  nli
 * it broke
 *
 * Revision 1.14  2003/07/30 20:42:29  nli
 * short job timeouts should actually be working correctly now.  empty timeouts are in there but untested
 *
 * Revision 1.13  2003/07/30 17:02:11  nli
 * casjobsadmin checks for ownership or admin
 *
 * Revision 1.12  2003/07/28 20:24:15  nli
 * privs added to jobs, jobsadmin and servers
 *
 * Revision 1.11  2003/07/23 21:11:06  nli
 * -outputloc arg removed from CasJobs.StartJob
 *     this is set only by the output proceesor
 * -hostip is correctly set in submitshortjob and queuethreadaction
 * -various changes in other stuff to make the above 2 thigns work
 *
 * Revision 1.10  2003/07/21 19:57:58  nli
 * untested outputcore
 *
 * Revision 1.9  2003/07/16 21:38:18  womullan
 *  added extract table
 *
 * Revision 1.8  2003/07/14 18:08:51  nli
 * -new method in jobsadmin -- CompleteCancel
 * -Core will cancel jobs that have not started yet (still will not timeout)
 *
 * Revision 1.7  2003/07/02 20:29:53  nli
 * --full lazy creation mydb support
 * --changed some *.aspx so non ms cronies can run it
 * --failed submitJob should set failed status
 *
 * Revision 1.6  2003/06/26 20:31:08  nli
 * IsInLowestQueueStatement made more robust
 *
 * Revision 1.5  2003/06/20 18:33:40  nli
 * added submitShortJob method in CasJobs
 *
 * Revision 1.4  2003/06/19 19:37:19  womullan
 *  users added
 *
 * Revision 1.3  2003/06/19 18:52:08  nli
 *
 * blah blah cvs
 *
 */
