using System;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Collections;
using System.Diagnostics;
using System.Threading;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using edu.jhu.Cas.Jobs;
using edu.jhu.Cas.Plot;
using edu.jhu.Cas.Servers;
using edu.jhu.Cas.Users;
using edu.jhu.Cas.Util;
using net.ivoa.VOTable;
using nom.tam.fits;
using System.Security.Cryptography;
using com.referentia.ps.psdatafilelib;

//using SoftwareFX.ChartFX.Lite;
namespace edu.jhu.Cas.Service {
    public class OutputThread : CJobsDBThread {
        internal static long serviceId = ID.SERVICE_ID;//should be in a file, param, etc.
        public const int DELAY = 15 * 1000;
        public static string nonQueryClause = " and outputtype not like '%query%' and outputtype not like '%monitor%' and outputtype not like '%HEARTBEAT%'";
        static internal CasJobs cJobs = new CasJobs();
        static internal CasUsers cUsers = new CasUsers();
        static internal CasJobsAdmin cAdmin = new CasJobsAdmin();
        static internal CasOutput cOut = new CasOutput();
        private const int JobLifeTime = 7;//a week        

        public override string ServiceName {
            get {
                return "Output Service";
            }
        }
        public override string ServiceDescription{
            get {
                return "Executes table extraction jobs.";
            }
        }
        public override int DefaultPanicMinutes {get {return 5;}}
        protected override void Halt() {}
        protected override void Run() {
            for (; ; ) {
                try {
                    if (State == CJobsDBState.RUNNING) {
                        FetchReady();
                    }
                    CycleComplete();
                }
                catch (Exception e) { CJobsService.Log(e.ToString(), EventLogEntryType.Error); }
                Thread.Sleep(DELAY);
            }
        }
        public void FetchReady() {
            Job[] jobs = cAdmin.FindJob(serviceId, "status = " + QUERY_STATUS.READY + nonQueryClause);
            if (jobs != null && jobs.Length > 0) {
                for (int x = 0; x < jobs.Length; x++) {
                    try {
                        ProcessJob(jobs[x]);
                    }
                    catch (Exception e) {
                        CJobsService.Log(e.ToString(), EventLogEntryType.Error);
                        cAdmin.FailJob(jobs[x].WebServicesID, jobs[x].JobID, e.Message, jobs[x].Created_Table);
                        continue;
                    }
                }
            }
        }
        public void ProcessJob(Job job) {
            string connectionString;
            job.Target = job.Target.ToLower();
            CJobsService.Log("Outputing " + job.JobID + " " + job.TaskName, EventLogEntryType.Information);
            Server mydbS = cUsers.MyDBServerObject(job.WebServicesID);
            if (job.Target.CompareTo("mydb") == 0)
                connectionString = mydbS.ConnectionString;
            else
                connectionString = cUsers.TheirDBConnection(job.Target);
            User user = cUsers.FindUser(serviceId, "webservicesid = " + job.WebServicesID)[0];
            DataSet ds = new DataSet();
            cAdmin.StartJob(job.WebServicesID, job.JobID, mydbS.Host, job.Created_Table);
            SqlCommand com = new SqlCommand(job.ModifiedQuery, new SqlConnection(connectionString));
            SqlDataReader reader = null;
            try {
                com.Connection.Open();
                string key = job.OutputType.ToLower();
                if (key.CompareTo("csv") == 0 || key.CompareTo("fits") == 0 || key.CompareTo("tcsv") == 0) {
                    try {
                        reader = com.ExecuteReader();
                    }
                    catch (Exception e) {
                        cAdmin.FailJob(job.WebServicesID, job.JobID, e.Message + " " + e.StackTrace, job.Created_Table);
                        return;
                    }
                }
                else if (key.CompareTo("plot") != 0) {
                    try {
                        SqlDataAdapter da = new SqlDataAdapter(com);
                        da.Fill(ds);
                        com.Connection.Close();
                    }
                    catch (Exception e) {
                        cAdmin.FailJob(job.WebServicesID, job.JobID, e.Message + " " + e.StackTrace, job.Created_Table);
                        return;
                    }
                }
                string path = cOut.path(job.OutputType);
                string url = cOut.url(job.OutputType);
                string name = job.TaskName.Trim() + "_" + user.UserID.Trim();
                switch (key) {
                    case "csv":
                        name += ".csv";
                        name = getRealName(path, name);
                        DataConverter.reader2CSVFile(reader, path + name);
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "csv output complete", url + name, 0);
                        break;
                    case "tcsv":
                        name += ".csv";
                        name = getRealName(path, name);
                        FileStream fstream = File.OpenWrite(path + name);
                        using (StreamWriter sw = new StreamWriter(fstream)) {
                            PSWriter psw = new PSWriter();
                            psw.WriteDataReader(reader, sw);
                        }
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "tcsv output complete", url + name, 0);
                        break;
                    case "fits":
                        name += ".fit";
                        name = getRealName(path, name);
                        Fits.TempDirectory = "C:\\Temp\\";
                        Fits.Write(reader, path + name);
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "fits output complete", url + name, 0);
                        break;
                    case "dataset":
                        name += ".xml";
                        name = getRealName(path, name);
                        FileStream fs = new FileStream(path + name, System.IO.FileMode.Create);
                        try {
                            XmlSerializer serializer = new XmlSerializer(typeof(DataSet));
                            serializer.Serialize(fs, ds);
                        }
                        finally {
                            try { fs.Close(); }
                            catch { }
                        }
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "dataset output complete", url + name, 0);
                        break;
                    case "votable":
                        name += ".xml";
                        name = getRealName(path, name);
                        VOTABLE votable = VOTableUtil.DataSet2VOTable(ds);
                        FileStream fs1 = new FileStream(path + name, System.IO.FileMode.Create);
                        try {
                            XmlSerializer serializer = new XmlSerializer(typeof(VOTABLE));
                            serializer.Serialize(fs1, votable);
                        }
                        finally { try { fs1.Close(); } catch { } }
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "votable output complete", url + name, 0);
                        break;
                    case "plot":
                        string[] table_xcol_ycol = job.Params.Split(',');
                        Plotter p = new Plotter(connectionString, table_xcol_ycol[0], table_xcol_ycol[1], table_xcol_ycol[2], com.CommandText);
                        name += ".png";
                        name = getRealName(path, name);
                        p.PlotAndSaveTable(path + name);
                        cAdmin.FinishedOutputJob(job.WebServicesID, job.JobID,
                            "plot output complete", url + name, 0);
                        break;
                }
            }
            catch (Exception e) {
                cAdmin.FailJob(job.WebServicesID, job.JobID,
                                e.Message + " " + e.StackTrace, job.Created_Table);
                Console.WriteLine("FAILED OUTPUT: " + e.ToString());
            }
            finally {
                try { reader.Close(); }
                catch { }
                try { com.Cancel(); }
                catch { }
                try { com.Connection.Close(); }
                catch { }
            }
            /*
            if(File.Exists(path+name) && false){//disable for now
                FileStream fs = new FileStream(path+name,FileMode.Open);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] rst = md5.ComputeHash(fs);
                string code = "";
                //code = Convert.ToBase64String(rst,0,rst.Length-1);
				
                for(int x=0;x<rst.Length;x=x+2){
                    //code+=rst[x].ToString();
                }
                code+=" *"+name;
				
                Console.WriteLine(code);
				
                string crcPath = path+name+".md5";
                File.Delete(crcPath);
                Console.WriteLine(crcPath);
                StreamWriter sw = new StreamWriter(crcPath);
                Console.WriteLine(code);
                sw.Write(code.ToString());
                sw.Close();
                fs.Close();
            }
            */
        }
        private string getRealName(string path, string name) {
            string tmp = name.Clone().ToString();
            for (int x = 0; x < 999; x++) {
                if (File.Exists(path + tmp))
                    tmp = name.Replace(".", "_" + x + ".");
                else
                    break;
            }
            return tmp;
        }
    }
}

