using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetSiemensPLCToolBoxLibrary;
using DotNetSiemensPLCToolBoxLibrary.Projectfiles;
using DotNetSiemensPLCToolBoxLibrary.DataTypes.Projectfolders;
using DotNetSiemensPLCToolBoxLibrary.DataTypes.Blocks;
using DotNetSiemensPLCToolBoxLibrary.DataTypes.Projectfolders.Step7V5;
using DotNetSiemensPLCToolBoxLibrary.DataTypes.Blocks.Step7V5;
using System.Data.SqlClient;
using System.Data;
using Security; 

public partial class app_custom_screens_IHConfiguration_data_sources_configuration_v2_api_upload_project : System.Web.UI.Page
{
    public class DataBlock
    {
        public string Name { get; set; }
        public int TagsCount { get; set; }
    }

    private class FileInfo
    {
        public string Name { get; set; }
        public string Path { get; set; }
    }

    private String connectionString = ConfigurationManager.ConnectionStrings["SYSTEM"].ConnectionString;
    private FileInfo fileinfo = null; 

    protected void Page_Load(object sender, EventArgs e)
    {
        bool failed = false; string json = "";
        
        string action = null; 
        try
        {
            HttpFileCollection fileCollection = Request.Files;
            int accountNumber = Convert.ToInt32(Request["accountNumber"]);
            int agentId = Convert.ToInt32(Request["agentId"]);
            string filename = (Request["filename"] != null) ? Request["filename"].ToString() : null;

            if (!string.IsNullOrEmpty(filename))
            {
                string internalPath = "\\app\\custom-screens\\IHConfiguration\\data-sources-configuration-v2\\plc_projects_uploaded\\";
                string path = AppDomain.CurrentDomain.BaseDirectory + internalPath;
                string filepath = path + filename;
                fileinfo = new FileInfo() { Path = filepath, Name = filename }; 
            }

            action = Request["action"].ToString();

            object response = null; 
            switch (action.ToUpper())
            {
                case "UPLOAD":
                    response = this.UploadProjectAndGetFolders(); 
                    break; 
                case "GETDBS":
                    string folderName = Request["folderName"].ToString(); 
                    if (!string.IsNullOrEmpty(folderName))
                        response = this.GetDBs(accountNumber, agentId, folderName); 
                    break; 
            }

            if (response != null)
            {
                System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
                json = jss.Serialize(response);
                Response.Clear();
                Response.ContentType = "application/json; charset=utf-8";
                Response.Write(json);
                Response.End();
            }
        }
        catch (Exception ex)
        {
            failed = true; 
        }

        if (failed)
        {
            json = "{\"status\":\"FAILED\"}";
            Response.Clear();
            Response.ContentType = "application/json; charset=utf-8";
            Response.Write(json);
            Response.End();
        }
    }

    private object UploadProjectAndGetFolders()
    {
        bool failed = false; 
        try
        {
            FileInfo finfo = this.UploadProject();
            List<string> folderNames = new List<string>(); 
            if (finfo != null)
            {
                //System.Threading.Thread.Sleep(5000); 
                Project tmp = Projects.LoadProject(finfo.Path, false);

                ProjectFolder pf = null;
                int pfCount = 0;
                while (pf == null && pfCount < 5)
                {
                    try
                    {
                        pfCount++;
                        pf = tmp.ProjectStructure;
                    }
                    catch (Exception ex) { }
                }

                List<BlocksOfflineFolder> blocksOfflineFolders = new List<BlocksOfflineFolder>();
                if (tmp.ProjectStructure != null && tmp.ProjectStructure.SubItems != null)
                {
                    blocksOfflineFolders = GetPLCBlocksOfflineFolders(tmp.ProjectStructure.SubItems);
                    blocksOfflineFolders.ForEach(bof => folderNames.Add(this.GetOfflineFolderName((ProjectFolder)bof))); 
                }
            }

            return new { status = "OK", filename = finfo.Name, folders = folderNames }; 
        }
        catch (Exception ex)
        {
            failed = true; 
            return new { status = "FAILED" }; 
        }
    }

    private string GetOfflineFolderName(ProjectFolder bof)
    {
        if (bof.Parent != null && bof.Parent.Parent != null)
        {
            return GetOfflineFolderName(bof.Parent);
        }
        else
        {
            return bof.Name;
        }
    }

    private object GetDBs(int accountNumber, int agentId, string folderName)
    {
        bool failed = false; 
        try
        {
            List<DataBlock> dataBlocks = new List<DataBlock>();

            Project tmp = Projects.LoadProject(fileinfo.Path, false);

            ProjectFolder pf = null;
            int pfCount = 0;
            while (pf == null && pfCount < 5)
            {
                try
                {
                    pfCount++;
                    pf = tmp.ProjectStructure;
                }
                catch (Exception ex) { }
            }

            List<BlocksOfflineFolder> blocksOfflineFolders = new List<BlocksOfflineFolder>();
            BlocksOfflineFolder folder = null; 
            if (tmp.ProjectStructure != null && tmp.ProjectStructure.SubItems != null)
            {
                blocksOfflineFolders = GetPLCBlocksOfflineFolders(tmp.ProjectStructure.SubItems);
                folder = blocksOfflineFolders.SingleOrDefault(bof => this.GetOfflineFolderName((ProjectFolder)bof).ToUpper() == folderName.ToUpper());
            }

            List<ProjectBlockInfo> blocks = ((IBlocksFolder)folder).readPlcBlocksList();
            List<string> agentDBS = this.GetAgentDBS(accountNumber, agentId);
            foreach (ProjectBlockInfo block in blocks)
            {
                try
                {
                    Block b = block.GetBlock();
                    if (b.BlockType == DotNetSiemensPLCToolBoxLibrary.DataTypes.PLCBlockType.DB)
                    {
                        if (agentDBS.Contains(b.BlockName))
                        {
                            dataBlocks.Add(new DataBlock()
                            {
                                Name = b.BlockName,
                                TagsCount = ((S7DataBlock)b).Structure.Children.Count
                                            + ((S7DataBlock)b).Structure.Children.Where(c => c.DataType == S7DataRowType.STRUCT).Sum(p => p.Children.Count)
                                            - ((S7DataBlock)b).Structure.Children.Where(c => c.DataType == S7DataRowType.STRUCT).ToList().Count
                                            + ((S7DataBlock)b).Structure.Children.Where(c => ((S7DataRow)c).IsArray).Sum(p => ((S7DataRow)p).ArrayStop[0] - ((S7DataRow)p).ArrayStart[0] + 1)
                                            - ((S7DataBlock)b).Structure.Children.Where(c => ((S7DataRow)c).IsArray).ToList().Count
                                            - ((S7DataBlock)b).Structure.Children.Where(c => ((S7DataRow)c).DataType == S7DataRowType.STRING || ((S7DataRow)c).DataType == S7DataRowType.CHAR).ToList().Count,
                            });
                        }
                    }
                }
                catch (Exception ex) { }
            }

            return new { status = "OK", datablocks = dataBlocks }; 
        }
        catch (Exception ex)
        {
            failed = true;
            return new { status = "FAILED" }; 
        }
    }

    private FileInfo UploadProject()
    {
        FileInfo finfo = null; 
        int accountNumber; int agentId;
        HttpFileCollection fileCollection = Request.Files;
        accountNumber = Convert.ToInt32(Request["accountNumber"]);
        agentId = Convert.ToInt32(Request["agentId"]);

        if (fileCollection.Count > 0){
            HttpPostedFile file = fileCollection[0];
            string path = AppDomain.CurrentDomain.BaseDirectory + "\\app\\custom-screens\\IHConfiguration\\data-sources-configuration-v2\\plc_projects_uploaded\\";

            Guid g = Guid.NewGuid();
            string filename = g.ToString() + ".zip";
            string filepath = Path.Combine(path, filename);
            file.SaveAs(filepath);

            finfo = new FileInfo() { Name = filename, Path = filepath }; 
        }
        return finfo; 
    }

    private List<BlocksOfflineFolder> GetPLCBlocksOfflineFolders(List<DotNetSiemensPLCToolBoxLibrary.DataTypes.Projectfolders.ProjectFolder> subItems)
    {
        List<BlocksOfflineFolder> blocks = new List<BlocksOfflineFolder>();
        foreach (ProjectFolder item in subItems)
        {
            if (item.GetType() == typeof(BlocksOfflineFolder))
            {
                blocks.Add((BlocksOfflineFolder)item);
            }

            if (item.SubItems != null)
            {
                blocks.AddRange(GetPLCBlocksOfflineFolders(item.SubItems));
            }
        }
        return blocks;
    }

    private List<string> GetAgentDBS(int accountNumber, int agentId)
    {
        List<string> dbs = new List<string>();
        try
        {
            SqlConnection sqlCon = new SqlConnection();
            sqlCon.ConnectionString = connectionString;

            SqlCommand comm = new SqlCommand("SYSTEM.GetAccountDBs", sqlCon);
            comm.CommandType = CommandType.StoredProcedure;

            SqlParameter sqlParam = new SqlParameter("@AccountNumber", SqlDbType.Int);
            sqlParam.Value = accountNumber;
            comm.Parameters.Add(sqlParam);

            SqlParameter sqlParam2 = new SqlParameter("@AgentId", SqlDbType.Int);
            sqlParam2.Value = agentId;
            comm.Parameters.Add(sqlParam2);

            DataSet ds = DALSecurity.CallSecuredProcedure(sqlCon, comm);
            if (ds != null && ds.Tables.Count > 0)
            {
                foreach (DataRow r in ds.Tables[0].Rows)
                {
                    dbs.Add(r["Name"].ToString().ToUpper()); 
                }
            }
        }
        catch (Exception ex)
        {
            //log error?
        }

        return dbs;
    }
}