using Helpers.Log;
using log4net;
using System;
using System.Reflection;
using System.Configuration; 
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
using System.Xml;
using System.Text;
using System.Xml.Serialization;

public partial class app_Registration_generate_download : System.Web.UI.Page
{
    private ILog logger = Logger.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);

    string AccountNumber;
    string SourceName;
    string AgentName;
    string AgentAddress; 

    protected void Page_Load(object sender, EventArgs e)
    {
        Boolean isLocalDebugging = true; 
        //generating downloads from local machine is not allowed.
        if (Request.IsLocal && !isLocalDebugging)
        {
            return;
        }

        bool ret = false;
        bool createSetup = false;
        bool xmlEdited = false;
        bool xmlEdited2 = false;
        bool copySources = false;

        string pathToDownload = "";
        System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
        try
        {
            logger.Debug("Starting generate download ..."); 

            AccountNumber = Request.Form["accountnumber"];
            SourceName = Request.Form["sourceName"];
            AgentName = Request.Form["agentName"];
            AgentAddress = HttpUtility.UrlDecode(Request.Form["agentAddress"]);

            logger.Debug(string.Format("Generating download for Account Number: [{0}] || SourceName: [{1}] || AgentName: [{2}] || AgentAddress: [{3}]", AccountNumber, SourceName, AgentName, AgentAddress)); 

            string IHAgentsSourcesFolder = ConfigurationManager.AppSettings["IHAgentsSourcesFolder"]; 
            SourceName = SourceName.ToUpper(); 
            string domain = Server.MapPath(this.AppRelativeTemplateSourceDirectory);

            DirectoryInfo buildsFolder = new DirectoryInfo(Server.MapPath("TempBuilds"));
            foreach (DirectoryInfo di in buildsFolder.GetDirectories(string.Format("*", SourceName.ToString(), AccountNumber.ToString())))
            {
                try
                {
                    di.Delete(true);
                }
                catch (Exception ex) { logger.Debug(string.Format("Could not delete folder [{0}] .", di.Name)); }
            }

            bool userFolderCreated = false;
            string userFolderPath = string.Empty; 
            while (!userFolderCreated)
            {
                string buildGUID = Guid.NewGuid().ToString().Substring(0, 4);
                userFolderPath = string.Format("TempBuilds\\{2}", Convert.ToString(SourceName), Convert.ToString(AccountNumber), buildGUID);

                System.IO.DirectoryInfo userFolder = new DirectoryInfo(Server.MapPath(userFolderPath));
                if (!userFolder.Exists) userFolderCreated = true; 
            }

            copySources = ExecuteCommandOnServer(domain, @"xcopy " + '"' + IHAgentsSourcesFolder + "\\" + Convert.ToString(SourceName) + "\\*.*" + '"' + " " + userFolderPath + @"\ /e /s");
            logger.Debug("Generate-download: copySources -> " + copySources.ToString()); 
            if (copySources == true)
            {
                string tempUserDomain = domain + userFolderPath + "\\";

                bool xmlsEdited = false;
                string xmlPath = "";
                string exeName = "";

                switch (SourceName)
                {
                    case "OPC":
                        logger.Debug("Generating OPCAgent download, editing XML with new values..."); 

                        exeName = "IHOPCAgent.exe"; 
                        xmlPath = "install\\program files\\AustralTek\\IHOPCAgent\\"; 

                        string IHXMLConfigName = "IHOPCAgentService.exe.config";
                        string IHNOOPCXMLConfigName = "IHOPCAgentService.exe.noopc.config";

                        xmlEdited = EditXML(tempUserDomain, IHXMLConfigName, xmlPath, AccountNumber, AgentName, AgentAddress, true);
                        logger.Debug(string.Format("XMLEdited: {0}", xmlEdited.ToString())); 

                        xmlEdited2 = EditXML(tempUserDomain, IHNOOPCXMLConfigName, xmlPath, AccountNumber, AgentName, AgentAddress, false);
                        logger.Debug(string.Format("XMLEdited2: {0}", xmlEdited2.ToString())); 

                        xmlsEdited = (xmlEdited && xmlEdited2); 
                        break; 
                    case "PLCSIEMENSS7":
                        logger.Debug("Generating PLCSIEMENSS7 Agent download, editing XML with new values..."); 

                        exeName = "IHPLCSiemensAgent.exe"; 
                        xmlPath = "install\\program files\\AustralTek\\IHPLCSiemensAgent\\";
                        string PLCXMLConfigName = "IHPLCSiemensAgentService.exe.config";
                        xmlEdited = EditXML(tempUserDomain, PLCXMLConfigName, xmlPath, AccountNumber, AgentName, AgentAddress, false);
                        logger.Debug(string.Format("XMLEdited: {0}", xmlEdited.ToString())); 

                        xmlsEdited = xmlEdited; 
                        break; 
                }

                if (xmlsEdited)
                {
                    logger.Debug("XMLEdited succesfully, executing command to compress files into setup.exe ..."); 
                    createSetup = ExecuteCommandOnServerFromBat(tempUserDomain, tempUserDomain + "compress.bat");

                    //bool signSetup = ExecuteCommandOnServer(tempUserDomain, @"kSignCMD.exe /d DZSOPCAgentInstaller /du http://www.dzsupervision.com /f DZScertificate.pfx /p Past2040 setup.exe");
                    //bool signSetup = ExecuteCommandOnServer(tempUserDomain, @"signtool sign /p Past2040 /f DZScertificate.pfx /d DZSOPCAgentInstaller /du http://www.dzsupervision.com /t http://timestamp.comodoca.com/authenticode /v setup.exe");
                    logger.Debug(string.Format("createSetup: {0}", createSetup.ToString())); 
                    if (createSetup == true)
                    {
                        logger.Debug("Generating path to download ..."); 

                        pathToDownload = VirtualPathUtility.GetDirectory(Request.Path); 
                        pathToDownload = (pathToDownload.Last() == '/') ? pathToDownload.Substring(0, pathToDownload.Length - 1) : pathToDownload;
                        pathToDownload += @"/" + userFolderPath + @"/" + exeName;

                        logger.Debug(string.Format("Path to download file: {0}", pathToDownload.ToString())); 
                        //userFolder = new DirectoryInfo(Server.MapPath("TempBuilds\\Build_"+Convert.ToString(AccountNumber)));
                        //foreach (DirectoryInfo folder in userFolder.GetDirectories())
                        //    folder.Delete(true);  

                        //foreach (FileInfo file in userFolder.GetFiles())
                        //    if (file.Name != "setup.exe") file.Delete();

                        ret = true;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            logger.Error(ex.Message, ex); 
            ret = false;
        }

        if (ret == true)
        {
            Response.Write(jss.Serialize(new { status = "OK", path = pathToDownload }));
        }
        else
        {
            Response.Write(jss.Serialize(new { status = "FAILED" }));
        }
    }

    private bool ExecuteCommandOnServer(string workingDirectory, string oneLineCommand)
    {
        logger.Debug("ExecuteCommandOnServer. WorkingDir: " + workingDirectory + " || command: " + oneLineCommand); 
        bool ret = false;
        try
        {
            // Create the ProcessInfo object
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo("cmd.exe");
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            psi.WorkingDirectory = workingDirectory;
            // Start the process
            System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi);
            // Open the batch file for reading
            //System.IO.StreamReader strm = System.IO.File.OpenText(strFilePath);
            // Attach the output for reading
            System.IO.StreamReader sOut = proc.StandardOutput;
            // Attach the in for writing
            System.IO.StreamWriter sIn = proc.StandardInput;
            // Write each line of the batch file to standard input
            sIn.WriteLine(@oneLineCommand);
            //strm.Close();
            // Exit CMD.EXE
            sIn.WriteLine("EXIT");
            // Close the process
            proc.Close();
            // Read the sOut to a string.
            string results = sOut.ReadToEnd().Trim();
            // Close the io Streams;
            sIn.Close();
            sOut.Close();
            ret = true;
        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }

    private bool ExecuteCommandOnServerFromBat(string workingDirectory, string pathToBat)
    {
        bool ret = false;
        try
        {
            // Create the ProcessInfo object
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo("cmd.exe");
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            psi.WorkingDirectory = workingDirectory;

            //string usernameString = "Administrator"; 
            //string PwString = "AustralTek2012";
            //string domain = null; 
            //char[] PasswordChars = PwString.ToCharArray();
            //System.Security.SecureString passwordString = new System.Security.SecureString();
            //foreach (char c in PasswordChars)
            //    passwordString.AppendChar(c);

            //psi.UserName = usernameString;
            //psi.Password = passwordString; 

            // Start the process
            System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi);
            // Open the batch file for reading
            System.IO.StreamReader strm = System.IO.File.OpenText(pathToBat);
            // Attach the output for reading
            System.IO.StreamReader sOut = proc.StandardOutput;
            // Attach the in for writing
            System.IO.StreamWriter sIn = proc.StandardInput;
            // Write each line of the batch file to standard input

            while (strm.Peek() != -1)
            {
                sIn.WriteLine(strm.ReadLine());
            }
            strm.Close();
            // Exit CMD.EXE
            sIn.WriteLine("EXIT");
            // Close the process
            proc.Close();
            // Read the sOut to a string.
            string results = sOut.ReadToEnd().Trim();
            // Close the io Streams;
            sIn.Close();
            sOut.Close();
            ret = true;
        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }

    private bool EditXML(string tempUserDomain, string IHXMLConfigName, string xmlPath, string AccountNumber, string name, string address, bool writeOPC)
    {
        bool ret = false;
        try
        {

            Dictionary<string, string> DefaultConfigurationValuesDictionary = DAL.GetDefaultConfigurationValuesForSetup(AccountNumber);
            XDocument xdoc = XDocument.Load(tempUserDomain + xmlPath + IHXMLConfigName);

            foreach (XElement elem in xdoc.Descendants("Name"))
            {
                elem.Value = ""; 
            }
            foreach (XElement elem in xdoc.Descendants("IHServerHost"))
            {
                elem.Value = DefaultConfigurationValuesDictionary["DefaultIHServerHost"];
            }
            foreach (XElement elem in xdoc.Descendants("IHServerPort"))
            {
                elem.Value = DefaultConfigurationValuesDictionary["DefaultIHServerPort"];
            }
            if (writeOPC)
            {
                foreach (XElement elem in xdoc.Descendants("Address"))
                {
                    elem.Value = DefaultConfigurationValuesDictionary["DefaultOPCServer"];
                }
            }
            if (!String.IsNullOrEmpty(address))
            {
                String addrs = String.Empty;
                switch (SourceName)
                {
                    case "OPC":
                        addrs = address.ToString();
                        break;
                    case "PLCSIEMENSS7":
                        PLCConnectionConfiguration PLCConnConfig = new PLCConnectionConfiguration();

                        XmlSerializer ser = new XmlSerializer(typeof(PLCConnectionConfiguration));
                        StringReader rdr = new StringReader(address);
                        PLCConnConfig = (PLCConnectionConfiguration)ser.Deserialize(rdr);

                        MemoryStream ms = new MemoryStream();

                        //Create our own namespaces for the output
                        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

                        //Add an empty namespace and empty value
                        ns.Add("", "");
                        XmlWriterSettings settings = new XmlWriterSettings();
                        settings.OmitXmlDeclaration = true;
                        settings.Encoding = new UTF8Encoding(false);
                        settings.Indent = true;
                        settings.IndentChars = "    ";
                        settings.NewLineHandling = NewLineHandling.Replace;
                        settings.NewLineChars = "\r\n";
                        settings.NewLineOnAttributes = true;

                        using (StringWriter textWriter = new StringWriter())
                        {
                            using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
                            {
                                ser.Serialize(xmlWriter, PLCConnConfig, ns);
                            }
                            addrs = textWriter.ToString();
                            //addrs = addrs.Replace("\r\n", "");
                        }
                        break;
                }

                foreach (XElement elem in xdoc.Descendants("Address"))
                {
                    elem.Value = Convert.ToString(addrs);
                }
            }
            if (!String.IsNullOrEmpty(name))
            {
                foreach (XElement elem in xdoc.Descendants("Name"))
                {
                    elem.Value = Convert.ToString(name);
                }
            }
            foreach (XElement elem in xdoc.Descendants("Account"))
            {
                elem.Value = Convert.ToString(AccountNumber);
            }

            xdoc.Save(tempUserDomain + xmlPath + IHXMLConfigName);
            ret = true;

        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }

}