using AppData;
using Newtonsoft.Json;
using NKC_SDK;
using SteamWare;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Web.Http;

namespace NKC_WF.Controllers
{
    public class PrintQueueController : ApiController
    {
        /// <summary>
        /// oggetto static/singleton per fare chiamate sul datalayer
        /// </summary>
        protected DataLayer DLMan = new DataLayer();

        #region classi gestione PJQ

        /// <summary>
        /// Conteggio elementi in attesa stampa da DB
        /// </summary>
        protected int countWaitingDb
        {
            get
            {
                int answ = 0;
                // resetto conteggio in redis...
                DS_Report.PrintJobQueueDataTable tabPJQ = DLMan.taPJQ.getWaiting();
                if (tabPJQ != null)
                {
                    answ = tabPJQ.Count;
                }
                return answ;
            }
        }
        /// <summary>
        /// Conteggio elementi in attesa stampa da DB che fanno parte di un SET di queue
        /// </summary>
        protected int countWaitingDbQueueMult(string queueSet)
        {
            int answ = 0;
            // resetto conteggio in redis...
            DS_Report.PrintJobQueueDataTable tabPJQ = DLMan.taPJQ.getWaiting();
            if (tabPJQ != null)
            {
                var selQueue = tabPJQ.Where(x => queueSet.Contains($"|{x.prtName}|")).ToList();
                if (selQueue != null)
                {
                    answ = selQueue.Count;
                }
            }
            return answ;
        }
        /// <summary>
        /// Carica i dati richiesti dal report dalla StoredProcedure (filtrando quindi...) e restituisce Dictionary [nome RDS / tab RDS]
        /// </summary>
        /// <param name="tipoReport"></param>
        /// <param name="keyParam">cod UDC</param>
        /// <returns>tabella dati</returns>
        private Dictionary<string, DataTable> caricaDati(reportRichiesto tipoReport, string keyParam)
        {
            int intIdx = 0;
            Dictionary<string, DataTable> answ = new Dictionary<string, DataTable>();
            DataTable tab = new DataTable();
            // FIXME TODO...
            string qrCodeBaseUrl = "";
            string imagePath = ""; //"http://seriate.steamware.net:8083/NKC/PartsImg/";
            switch (tipoReport)
            {
                case reportRichiesto.binPost:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepBin.GetData(intIdx, true, imagePath, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocBin"), tab);
                    break;
                case reportRichiesto.binPre:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepBin.GetData(intIdx, false, imagePath, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocBin"), tab);
                    break;
                case reportRichiesto.bunkGroup:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepBunkGroup.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocBunkGroup"), tab);
                    break;
                case reportRichiesto.bunkList:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepBunkList.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocBunkList"), tab);
                    break;
                case reportRichiesto.cart:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepCart.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocCart"), tab);
                    break;
                case reportRichiesto.offline:
                case reportRichiesto.part:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepPart.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocPart"), tab);
                    break;
                case reportRichiesto.otherPart:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepOtherPart.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocOtherPart"), tab);
                    break;
                case reportRichiesto.cartIRKGroup:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepIRKSum.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocIRKGroup"), tab);
                    break;
                case reportRichiesto.cartIRKList:
                    int.TryParse(keyParam, out intIdx);
                    tab = (DataTable)DLMan.taRepIRK.GetData(intIdx, qrCodeBaseUrl);
                    answ.Add(memLayer.ML.cdv("ReportDS_DocIRKList"), tab);
                    break;
                default:
                    break;
            }
            tab.Dispose();
            return answ;
        }

        /// <summary>
        /// Calcola report da tipo + nome coda...
        /// </summary>
        /// <param name="tipo"></param>
        /// <param name="queueName"></param>
        /// <returns></returns>
        protected reportRichiesto reportByTipo(string tipo, string queueName)
        {
            reportRichiesto report = reportRichiesto.bunkGroup;
            switch (tipo)
            {
                case "docStack":
                    if (queueName == "queueBunkDetail")
                    {
                        report = reportRichiesto.bunkList;
                    }
                    else
                    {
                        report = reportRichiesto.bunkGroup;
                    }
                    break;
                case "docBinPre":
                    report = reportRichiesto.binPre;
                    break;
                case "docBinPost":
                    report = reportRichiesto.binPost;
                    break;
                case "docCart":
                    report = reportRichiesto.cart;
                    break;
                case "docCartIRKSum":
                    report = reportRichiesto.cartIRKGroup;
                    break;
                case "docCartIRK":
                    report = reportRichiesto.cartIRKList;
                    break;
                case "docPart":
                    report = reportRichiesto.part;
                    break;
                case "docOtherPart":
                    report = reportRichiesto.otherPart;
                    break;
                case "docOffline":
                    report = reportRichiesto.offline;
                    break;
                default:
                    break;
            }
            return report;
        }

        #endregion

        #region REST api call

        /// <summary>
        /// Restituisce numero jobs aperti (stato = 0...), se 0 = NESSUNO
        /// GET: api/PrintQueue
        /// </summary>
        /// <returns></returns>
        public int Get()
        {
            // restituisco...
            int answ = 0;
            string redVal = memLayer.ML.getRSV(ComLib.redQueueCount);
            // cerco in redis se ci sia chiave..
            if (!string.IsNullOrEmpty(redVal))
            {
                // recupero
                int.TryParse(redVal, out answ);
            }
            else
            {
                // recupero da db e salvo
                answ = countWaitingDb;
                memLayer.ML.setRSV(ComLib.redQueueCount, answ.ToString(), memLayer.ML.CRI("cacheQueueSec"));
                // chiudo gli zombie (stampe non chiuse)...
                DLMan.taPJQ.chiudiZoombie(DateTime.Now.AddMilliseconds(-memLayer.ML.CRI("zombieMsTime")));
            }
            return answ;
        }

        /// <summary>
        /// Elenco dei jobs aperti per la coda indicata
        /// GET: api/PrintQueue/queue_01
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<reportData> Get(string id)
        {
            List<reportData> answ = new List<reportData>();
            // recupero da DB...
            DS_Report.PrintJobQueueDataTable tabPJQ = DLMan.taPJQ.getByQueue(id);
            if (tabPJQ.Count > 0)
            {
                reportData currReport = new reportData();
                Dictionary<string, DataTable> currRdsData;
                // ciclo!
                foreach (var pjReq in tabPJQ)
                {
                    currRdsData = caricaDati(reportByTipo(pjReq.TipoReport, pjReq.prtName), pjReq.KeyParam);
                    // in base alla coda --> recupero i dati
                    currReport = new reportData()
                    {
                        ticketNum = pjReq.IdxPrintJob.ToString(),
                        rdsData = currRdsData
                    };
                    answ.Add(currReport);
                }
            }
            // compongo risposta...
            return answ;
        }

        /// <summary>
        /// Processa una chiamata POST per l'invio in blocco del risultato dell'elaborazione
        /// POST: api/PrintQueue
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public string Post()
        {
            string answ = "UNKN";
            // questa classe è derivata da Controller.Response... x cui recupero lo stream in altro modo...
            string content = "";
            System.Web.HttpContext.Current.Request.InputStream.Position = 0;
            using (var reader = new StreamReader(System.Web.HttpContext.Current.Request.InputStream, System.Text.Encoding.UTF8, true, 4096, true))
            {
                content = reader.ReadToEnd();
            }
            //Rest
            System.Web.HttpContext.Current.Request.InputStream.Position = 0;
            // procedo a deserializzare in blocco l'oggetto...
            try
            {
                // deserializzo.
                printTask printAnsw = JsonConvert.DeserializeObject<printTask>(content);
                // verifico se mi abbia dato esito 1 --> aggiorno DB!
                if (printAnsw != null)
                {
                    int idxPJQ = 0;
                    int.TryParse(printAnsw.ticketNum, out idxPJQ);
                    DLMan.taPJQ.updateStato(idxPJQ, printAnsw.newStatus);
                    // resetto conteggio in redis...
                    memLayer.ML.setRSV(ComLib.redQueueCount, countWaitingDb.ToString(), memLayer.ML.CRI("cacheQueueSec"));
                    // svuoto code redis salvate..
                    memLayer.ML.redFlushKey(ComLib.redQueueCountSet);
                    answ = "OK";
                }
            }
            catch
            { }
            // restituisco esito!
            return answ;
        }

        #endregion
    }
}
