using OliviaAddInPro.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OliviaAddInPro.Services.LanzaSrv
{
    /*
     * ejecuta antiguo
     * */
    public class LanzaOlvServ
    {
        //*************************************************************************************
        //Variables         
        /**
         * Cadena general de escritura de parámetros de configuración para envío por socket
         */
        public string str_cfg;
        /**
         * Cadena general de escritura de parámetros para envío por socket
         */
        public string str;

        public string NombreTratamiento;
        

        //*************************************************************************************
        public LanzaOlvServ()
        {
            str = "";
        }
         ~LanzaOlvServ() // destructor (finalizers)
        {
            // cleanup statements...
        }

        public Respuesta<bool> ejec(string NTratamiento)
        {            
            NombreTratamiento = NTratamiento;
            add_cfg_comun();       

            //lanza proceso OliviaTask
            var res = lanza();
            if (!res.Value)
            {
                res.Error.Add("Error al arrancar OliviaTask (programa de procesado de datos): No ha arrancado correctamente la instancia OliviaTask");
                return res;
            }

            return res;
        }

        /**
         * Añade al str de cfg los parametros de configuración comunes a limpieza y recogida
         */
        private void add_cfg_comun()
        {
            str_cfg = str_cfg +
                //campos de la red navegable
                /*
                GeneralDef.EjecGeoParamSep + GeneralDef.GTC_onew + GeneralDef.EjecGeoParamIgual + ComunDef.CamposNW.cons_onew + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTC_kph + GeneralDef.EjecGeoParamIgual + ComunDef.CamposNW.cons_kph + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTC_fow + GeneralDef.EjecGeoParamIgual + ComunDef.CamposNW.cons_fow + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTC_name + GeneralDef.EjecGeoParamIgual + ComunDef.CamposNW.cons_name + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTA_TF + GeneralDef.EjecGeoParamIgual + ComunDef.AtributosNW.atr_TF + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTA_FT + GeneralDef.EjecGeoParamIgual + ComunDef.AtributosNW.atr_FT + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTA_N + GeneralDef.EjecGeoParamIgual + ComunDef.AtributosNW.atr_N + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTA_pedes + GeneralDef.EjecGeoParamIgual + ComunDef.AtributosNW.atr_pedes + " " +
                */
                //nombre del tratamiento
                GeneralDef.EjecGeoParamSep + GeneralDef.GG_strtto + GeneralDef.EjecGeoParamIgual + NombreTratamiento + " " +
                //paths de archivos
                GeneralDef.EjecGeoParamSep + GeneralDef.GG_pd + GeneralDef.EjecGeoParamIgual + OliviaGlob.Paths.PathData + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GG_pn + GeneralDef.EjecGeoParamIgual + OliviaGlob.Paths.PathNW + " " +
                //nombres de cols de sector y secuencia
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_camp_sector + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.consulta_sector + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_camp_secuencia + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.consulta_secuen + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_camp_objectid + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.camp_oid + " " +
                //giro max y desv
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_girmax + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.giro_max + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_desv_max + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.desv_max + " " +
                GeneralDef.EjecGeoParamSep + GeneralDef.GTO_desv_max_abs + GeneralDef.EjecGeoParamIgual + ComunDef.CamposCom.desv_max_abs + " ";
            //LimpiezaDef.Campos.consulta_sector;
        }

        /**
         * Arranca el proceso OliviaTask con los parámetros correspondientes
         */
        private Respuesta<bool> lanza()
        {
            Process[] pg;
            string args;
            ProcessStartInfo pfi;
            var res = new Respuesta<bool>();

            try
            {
                int tipoEjec=-1;
                if (OliviaGlob.IsLimp())
                    tipoEjec = 0;
                else if (OliviaGlob.IsReco())
                    tipoEjec = 1;
                //van ParamN parámetros, sin incluir, si se añaden, incrementar ParamN
                args = GeneralDef.EjecGeoParamSep + GeneralDef.GG_tipo + GeneralDef.EjecGeoParamIgual + tipoEjec.ToString() + " " +
                        GeneralDef.EjecGeoParamSep + GeneralDef.GG_ip + GeneralDef.EjecGeoParamIgual + OliviaGlob.Conexion.Ip + " " +
                        GeneralDef.EjecGeoParamSep + GeneralDef.GG_port + GeneralDef.EjecGeoParamIgual + OliviaGlob.Conexion.Puerto + " " +
                        GeneralDef.EjecGeoParamSep + GeneralDef.GG_tout + GeneralDef.EjecGeoParamIgual + OliviaGlob.Conexion.TiempoOutSocket + " " +
                        GeneralDef.EjecGeoParamSep + GeneralDef.GG_pt + GeneralDef.EjecGeoParamIgual + OliviaGlob.Paths.PathTemp + " " +
                        GeneralDef.EjecGeoParamSep + GeneralDef.GG_pcfg + GeneralDef.EjecGeoParamIgual + "";

                pfi = new ProcessStartInfo(OliviaGlob.Paths.PathExeOlivia, args);
                pfi.UseShellExecute = false;
                System.Diagnostics.Process.Start(pfi);                

                //comprueba que haya arrancado OliviaTask
                //le da 2 seg de margen para que arranque
                pg = Is_process(GeneralDef.NombOlvTasks, 2, true);
                if (pg == null)
                {
                    res.Error.Add(string.Format("No está OliviaTask, args= {0}", args));
                    res.Value = false;
                    return res;
                }
            }
            catch (Exception e)
            {
                res.Error.Add(string.Format("Error al lanzar proceso, args= {0}", e.Message));
                res.Value = false;
                return res;
            }
            res.Value = true;
            return res;
        }


        /**
         * Itera para comprobar que ha arrancado bien un proceso, o ver si está arrancado
         * int t_max : seg espera
         * bool espera_start : si true, se quiere esperar t_max a que arranque, 
         * si false, se quiere esperar a que se cierre
         * Devuelve el proceso si está, para cancelarlo, y null si no está
         */
        public Process[] Is_process(string nombproc, int t_max, bool espera_start)
        {
            bool esta_geo = !espera_start;
            int veces = 0;
            int veces_max;
            int milis_sleep = 50;

            if (t_max <= 0)
                t_max = 1;
            veces_max = t_max * 1000 / milis_sleep;

            Process[] pg = new Process[0];

            //si ya está arrancado y se quiere esperar a que se cierre, esta_geo=true y espera_start=false;
            //por lo que se cumple !espera_start && esta_geo
            //tiene que esperar si esta_geo==true
            //cuando se quiere esperar a que arranque, esta_geo=false y espera_start=true
            //por lo que se cumple (espera_start && !esta_geo)
            //en este caso, tiene que esperar si esta_geo==False
            while (((espera_start && !esta_geo) || (!espera_start && esta_geo)) && (veces < veces_max))
            {
                try
                {
                    pg = Process.GetProcessesByName(nombproc);
                    if (pg.Length == 0)
                        esta_geo = false;
                    else
                        esta_geo = true;
                }
                catch (InvalidOperationException)
                {
                    esta_geo = false;
                }

                if (((espera_start && !esta_geo) || (!espera_start && esta_geo)))
                {
                    veces++;
                    Thread.Sleep(milis_sleep);
                }
            }

            if (esta_geo)
                return pg;
            else
                return null;
        }

        /**
         * Comprueba si OliviaTask ha salido y le espera durante T seg. Si no, para la tarea
         * return true si ha terminado, false si no
         */
        public bool EsperaProcess(string nombproc)
        {
            bool esta_geo = true;
            Process[] pg;

            //le da 5 seg de margen para que se cierre
            pg = Is_process(nombproc, 5, false);
            esta_geo = (pg != null);

            if (esta_geo)
            {
                //mata a la fuerza la tarea
                try
                {
                    for (int i = 0; i < pg.Length; i++)
                    {
                        pg[i].Kill();
                        if (pg[i].WaitForExit(500))
                            esta_geo = false;
                    }
                }
                catch (Exception)
                {
                    esta_geo = false;
                }
            }
            return !esta_geo;
        }
    }
}
