using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;
using System.Configuration;
using System.Windows.Threading;
//using cosifacile.comodoServices;
using cosicomodo.quantycaReference;
using System.Text.RegularExpressions;
using System.Security.Cryptography;

namespace cosifacile
{
    /// <summary>
    /// Logica di interazione per LeggiCodice.xaml
    /// </summary>
    public partial class LeggiCodice : Page
    {
        public static SerialPort serialPort;
        MainPage parentWindow;
        public ServiceLayer sl = new ServiceLayer();
        DispatcherTimer timer = new DispatcherTimer();
        static int cTimerSec;
        readType cardororder = new readType();
        bool toDetails = false;

        public LeggiCodice(readType rt)
        {
            InitializeComponent();
            cardororder = rt;
            if (rt == readType.Card)
                lblOrder.Visibility = System.Windows.Visibility.Hidden;
            else
                lblCard.Visibility = System.Windows.Visibility.Hidden;
            helpMessage.Text = "SE HAI BISOGNO DI ASSISTENZA PER IL TUO ORDINE\n\nUSA IL CITOFONO POSTO SULLA DESTRA";
        }

        public LeggiCodice()
        {
            InitializeComponent();
        }

        private void LeggiCarta(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                parentWindow.logMsg("Ricevuto valore da barcode");
                string code = "";
                int bytes = serialPort.BytesToRead;
                if (bytes > 0)
                {
                    byte[] buffer = new byte[bytes];
                    serialPort.Read(buffer, 0, bytes);
                    var data = System.Text.Encoding.UTF8.GetString(buffer);
                    code = data.ToString();
                    code = Regex.Replace(code, "\r", "");
                    parentWindow.logMsg("Letto codice: " + code);
                    //serialPort.Close();
                }
                this.Dispatcher.BeginInvoke(new SetPageDeleg(si_DataReceived), code);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private delegate void SetPageDeleg(string code);
//        delegate Vincita aspettaVincitaAsincrona(string aCode, Scontrino aScontrino, beCustomer aPlayCustomer, string aOcrFile);
        private async void si_DataReceived(string code)
        {
            try
            {

                string[] closingCards = Regex.Split(parentWindow.rp.closingCards, ";");
                foreach (string current in closingCards)
                {

                    if (current == code)
                    {
                        try
                        {
                            serialPort.Close();
                        }
                        catch (Exception ex)
                        {
                            parentWindow.logError(ex);
                        }
                        finally
                        {
                            parentWindow.logMsg("Uscita programma con carta chiusura");
                            System.Environment.Exit(-1);
                        }
                    }
                }



                getOrdersOutputType orders = new getOrdersOutputType();
                string ordercode = "";
                string cardcode = "";
                if (this.cardororder == readType.Card)
                {
                    if (code.Length < 13)
                    {
                        for (int i = code.Length; i < 13; i++)
                        {
                            code = "0" + code;
                        }
                    }
                    cardcode = code;
                }

                else
                    ordercode = code;

                grdLoading.Visibility = System.Windows.Visibility.Visible;
                var slowTask = Task<statusType>.Factory.StartNew(() => Leggi(ordercode, cardcode, out orders, parentWindow.rp));
                statusType stat = await (slowTask);

                //statusType stat = parentWindow.sl.getOrders(ordercode, cardcode, out orders, parentWindow.rp.settings);

                getOrdersOutputType ordersToShow = new getOrdersOutputType();

                timer.Stop();
                parentWindow.publicOrders = orders;
                if (!Boolean.Equals(orders, null))
                {

                    List<sezioniOrdineType> listOrders = new List<sezioniOrdineType>();
                    //Devo controllare quanti ordini buoni ci sono
                    parentWindow.logMsg(string.Format("Trovati {0} ordini", orders.ordini.Length.ToString()));

                    foreach (sezioniOrdineType current in orders.ordini)
                    {
                        if ((current.testata.ordineBase.statoOrdine == "PRONTO_PER_IL_RITIRO" || current.testata.ordineBase.statoOrdine == "SLOT_MANCATO")  && current.testata.ordineBase.tipoServizio == "CC")
                        {
                            listOrders.Add(current);
                        }
                    }
                    parentWindow.logMsg(string.Format("Trovati {0} ordini per pronti per il ritiro", listOrders.Count));
                    ordersToShow.ordini = new sezioniOrdineType[listOrders.Count()];
                    int ordersToShowIndex = 0;
                    foreach (sezioniOrdineType current in listOrders)
                    {
                        ordersToShow.ordini[ordersToShowIndex] = current;
                        ordersToShowIndex++;
                    }

                    if (ordersToShow.ordini.Count() > 0)
                    {
                        callAutoDialer();
                        if (parentWindow.rp.modeType == 2)
                        {//vado direttamente al picking
                            parentWindow.logMsg(string.Format("Trovato ordine {0} pronto vado direttamente al picking", ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente));
                            orderToDeliveryOutputType orderToDelivery = new orderToDeliveryOutputType();
                            string[] orderIds = new string[ordersToShow.ordini.Count()];
                            orderIds[0] = ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente;
                            for (int i = 0; i < ordersToShow.ordini.Count(); i++)
                            {
                                orderIds[i] = ordersToShow.ordini[i].testata.ordineBase.idOrdineUtente;
                            }
                            //statusType delStat = parentWindow.sl.orderToDelivery(orderIds, "", out orderToDelivery);
                            statusType delStat = parentWindow.sl.orderToDelivery(orderIds, out orderToDelivery, parentWindow.rp, false);
                            if (delStat.codiceStato == 200)
                            {
                                Parking sub = new Parking(orderToDelivery.idParcheggio);
                                parentWindow.Content = sub;
                            }
                            else
                            {
                                NoService sub = new NoService();
                                parentWindow.Content = sub;
                            }
                        }
                        else
                        {
                            if (ordersToShow.ordini.Count() > 1)
                            {
                                Orders od = new Orders(ordersToShow);
                                parentWindow.Content = od;
                            }
                            else
                            {
                                if ((ordersToShow.ordini[0].testata.ordineBase.statoOrdine == "PRONTO_PER_IL_RITIRO" || ordersToShow.ordini[0].testata.ordineBase.statoOrdine == "SLOT_MANCATO")  && ordersToShow.ordini[0].testata.ordineBase.tipoServizio == "CC")
                                {
                                    toDetails = isOrderKO(ordersToShow.ordini[0]);

                                    if (!toDetails)
                                    {
                                        parentWindow.logMsg(string.Format("Trovato ordine {0} pronto vado direttamente al picking", ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente));
                                        orderToDeliveryOutputType orderToDelivery = new orderToDeliveryOutputType();
                                        string[] orderIds = new string[1];
                                        orderIds[0] = ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente;
                                        //statusType delStat = parentWindow.sl.orderToDelivery(orderIds, "", out orderToDelivery);
                                        statusType delStat = parentWindow.sl.orderToDelivery(orderIds, out orderToDelivery, parentWindow.rp, false);
                                        if (delStat.codiceStato == 200)
                                        {
                                            Parking sub = new Parking(orderToDelivery.idParcheggio);
                                            parentWindow.Content = sub;
                                        }
                                        else
                                        {
                                            //OrderDetails od = new OrderDetails(orders);
                                            //parentWindow.Content = od;
                                            Orders od = new Orders(ordersToShow);
                                            parentWindow.Content = od;
                                        }

                                    }
                                    else
                                    {
                                        //OrderDetails od = new OrderDetails(orders);
                                        //parentWindow.Content = od;
                                        Orders od = new Orders(ordersToShow);
                                        parentWindow.Content = od;
                                    }

                                }
                                else
                                {
                                    Orders od = new Orders(ordersToShow);
                                    parentWindow.Content = od;
                                }
                            }
                        }
                    }
                    else
                    {
                        parentWindow.logMsg(string.Format("Nessun ordine pronto per il ritiro"));
                        grdNotFound.Visibility = System.Windows.Visibility.Visible;
                        grdLoading.Visibility = System.Windows.Visibility.Hidden;
                        timer.Start();
                    }
                }
                else
                {
                    parentWindow.logMsg(string.Format("Nessun ordine restituito da quantyca"));
                    grdNotFound.Visibility = System.Windows.Visibility.Visible;
                    grdLoading.Visibility = System.Windows.Visibility.Hidden;
                    timer.Start();
                }
            }
            catch (Exception ex)
            {
                parentWindow.logMsg(string.Format("Eccezione nel recupero ordini: {0}", ex.Message));
                grdNotFound.Visibility = System.Windows.Visibility.Visible;
                grdLoading.Visibility = System.Windows.Visibility.Hidden;
                timer.Start();
            }
        }

        private statusType Leggi(string idOrder, string idCartafedelta, out getOrdersOutputType oType, RetailPoint rp)
        {
            oType = new getOrdersOutputType();
            statusType tv = new statusType();
            try
            {
                tv = parentWindow.sl.getOrders(idOrder, idCartafedelta, out oType, rp);
            }
            catch (Exception ex)
            {
                parentWindow.logError(ex);
            }
            return tv;
        }

        private void TimerTick(object sender, EventArgs e)
        {
            try
            {
                //parentWindow.logMsg("DatiScontrino - TimerTick");
                cTimerSec -= 1;
                if (cTimerSec <= 0)
                {
                    exitPage();
                }

                else
                    lblTimer.Content = cTimerSec.ToString();
            }

            catch { }
        }

        private void exitPage()
        {
            parentWindow.logMsg("Uscita pagina lettura");
            timer.Stop();
            CosiComodo SUB = new CosiComodo();
            parentWindow.Content = SUB;
            parentWindow = null;
            SUB = null;
        }

        private void btnEsci_Click(object sender, RoutedEventArgs e)
        {
            exitPage();
        }

        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
            serialPort.Close();
            serialPort = null;
        }

        private void grd_MouseUp(object sender, MouseButtonEventArgs e)
        {
            string myValue = (((Grid)sender).Tag).ToString();
            txtCode.Text += myValue;
        }

        private async void grdConfirm_MouseUp(object sender, MouseButtonEventArgs e)
        {
            grdConfirm.MouseUp -= grdConfirm_MouseUp;
            if (!string.IsNullOrEmpty(txtCode.Text))
            {
                getOrdersOutputType orders = new getOrdersOutputType();
                string ordercode = "";
                string cardcode = "";
                if (this.cardororder == readType.Card)
                    cardcode = txtCode.Text;
                else
                    ordercode = txtCode.Text;

                string[] closingCards = Regex.Split(parentWindow.rp.closingCards, ";");
                foreach (string current in closingCards)
                {

                    if (current == txtCode.Text && !string.IsNullOrEmpty(txtCode.Text))
                    {
                        try
                        {
                            serialPort.Close();
                        }
                        catch (Exception ex)
                        {
                            parentWindow.logError(ex);
                        }
                        finally
                        {
                            parentWindow.logMsg("Uscita programma con codice chiusura");
                            System.Environment.Exit(-1);
                        }
                    }
                }

                grdLoading.Visibility = System.Windows.Visibility.Visible;
                var slowTask = Task<statusType>.Factory.StartNew(() => Leggi(ordercode, cardcode, out orders, parentWindow.rp));
                statusType stat = await (slowTask);

                //statusType stat = parentWindow.sl.getOrders(ordercode, cardcode, out orders, parentWindow.rp.settings);

                getOrdersOutputType ordersToShow = new getOrdersOutputType();

                try
                {
                    if (stat.codiceStato == 200)
                    {
                        List<sezioniOrdineType> listOrders = new List<sezioniOrdineType>();
                        //Devo controllare quanti ordini buoni ci sono
                        parentWindow.logMsg(string.Format("Trovati {0} ordini", orders.ordini.Length.ToString()));
                        foreach (sezioniOrdineType current in orders.ordini)
                        {
                            if ((current.testata.ordineBase.statoOrdine == "PRONTO_PER_IL_RITIRO" || current.testata.ordineBase.statoOrdine == "SLOT_MANCATO") && current.testata.ordineBase.tipoServizio == "CC")
                            {
                                listOrders.Add(current);
                            }
                        }
                        parentWindow.logMsg(string.Format("Trovati {0} ordini per pronti per il ritiro", listOrders.Count));
                        ordersToShow.ordini = new sezioniOrdineType[listOrders.Count()];
                        int ordersToShowIndex = 0;
                        foreach (sezioniOrdineType current in listOrders)
                        {
                            ordersToShow.ordini[ordersToShowIndex] = current;
                            ordersToShowIndex++;
                        }

                        if (ordersToShow.ordini.Count() == 0 && this.cardororder == readType.Card)
                        {
                            grdNotFound.Visibility = System.Windows.Visibility.Visible;
                            nfMessage.Text = "NESSUN ORDINE DA RITIRARE\nPER LA TUA CARTA FEDELTA'";
                            grdLoading.Visibility = System.Windows.Visibility.Hidden;
                            grdConfirm.MouseUp += grdConfirm_MouseUp;
                        }
                        else
                        {
                            if (ordersToShow.ordini.Count() > 0)
                            {
                                callAutoDialer();
                                // controllo modetype
                                if (parentWindow.rp.modeType == 2)
                                {//vado direttamente al picking
                                    parentWindow.logMsg(string.Format("Trovato ordine {0} pronto vado direttamente al picking", ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente));
                                    orderToDeliveryOutputType orderToDelivery = new orderToDeliveryOutputType();
                                    string[] orderIds = new string[ordersToShow.ordini.Count()];
                                    orderIds[0] = ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente;
                                    for (int i = 0 ; i < ordersToShow.ordini.Count() ; i++)
                                    {
                                        orderIds[i] = ordersToShow.ordini[i].testata.ordineBase.idOrdineUtente;
                                    }
                                    //statusType delStat = parentWindow.sl.orderToDelivery(orderIds, "", out orderToDelivery);
                                    statusType delStat = parentWindow.sl.orderToDelivery(orderIds, out orderToDelivery, parentWindow.rp, false);
                                    if (delStat.codiceStato == 200)
                                    {
                                        Parking sub = new Parking(orderToDelivery.idParcheggio);
                                        parentWindow.Content = sub;
                                    }
                                    else
                                    {
                                        NoService sub = new NoService();
                                        parentWindow.Content = sub;
                                    }
                                }
                                else
                                {
                                    if (ordersToShow.ordini.Count() > 1)
                                    {
                                        Orders od = new Orders(ordersToShow);
                                        parentWindow.Content = od;
                                    }
                                    else
                                    {
                                        timer.Stop();
                                        if ((ordersToShow.ordini[0].testata.ordineBase.statoOrdine == "PRONTO_PER_IL_RITIRO" || ordersToShow.ordini[0].testata.ordineBase.statoOrdine == "SLOT_MANCATO")  && ordersToShow.ordini[0].testata.ordineBase.tipoServizio == "CC")
                                        {
                                            // Controllo che sia un ordine corretto o meno

                                            toDetails = isOrderKO(ordersToShow.ordini[0]);

                                            if (!toDetails)
                                            {
                                                parentWindow.logMsg(string.Format("Trovato ordine {0} pronto vado direttamente al picking", ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente));
                                                orderToDeliveryOutputType orderToDelivery = new orderToDeliveryOutputType();
                                                string[] orderIds = new string[1];
                                                orderIds[0] = ordersToShow.ordini[0].testata.ordineBase.idOrdineUtente;
                                                //statusType delStat = parentWindow.sl.orderToDelivery(orderIds, "", out orderToDelivery);
                                                statusType delStat = parentWindow.sl.orderToDelivery(orderIds, out orderToDelivery, parentWindow.rp, false);
                                                if (delStat.codiceStato == 200)
                                                {
                                                    Parking sub = new Parking(orderToDelivery.idParcheggio);
                                                    parentWindow.Content = sub;
                                                }
                                                else
                                                {
                                                    //OrderDetails od = new OrderDetails(orders);
                                                    //parentWindow.Content = od;
                                                    Orders od = new Orders(ordersToShow);
                                                    parentWindow.Content = od;
                                                }
                                            }
                                            else
                                            {
                                                //OrderDetails od = new OrderDetails(orders);
                                                //parentWindow.Content = od;
                                                Orders od = new Orders(ordersToShow);
                                                parentWindow.Content = od;
                                            }
                                        }
                                        else
                                        {
                                            Orders od = new Orders(ordersToShow);
                                            parentWindow.Content = od;
                                        }
                                    }
                                }
                            }
                            else // ordine non trovato
                            {
                                parentWindow.logMsg(string.Format("Nessun ordine pronto per il ritiro"));
                                grdNotFound.Visibility = System.Windows.Visibility.Visible;
                                grdLoading.Visibility = System.Windows.Visibility.Hidden;
                                grdConfirm.MouseUp += grdConfirm_MouseUp;
                            }
                        }
                    }
                    else // ordine non trovato
                    {
                        parentWindow.logMsg(string.Format("Nessun ordine pronto per il ritiro"));
                        grdNotFound.Visibility = System.Windows.Visibility.Visible;
                        grdLoading.Visibility = System.Windows.Visibility.Hidden;
                        grdConfirm.MouseUp += grdConfirm_MouseUp;
                    }
                }
                catch (Exception ex)
                {
                    parentWindow.logMsg(string.Format("Eccezione nel recupero ordini: {0}", ex.Message));
                    grdNotFound.Visibility = System.Windows.Visibility.Visible;
                    grdLoading.Visibility = System.Windows.Visibility.Hidden;
                    grdConfirm.MouseUp += grdConfirm_MouseUp;
                }
            }
        }

        bool isOrderKO(sezioniOrdineType customerOrders)
        {
            bool retValue = false;
            foreach (articoloOrdineType current in customerOrders.dettaglio)
            {
                if(current.articoloBase.quantita == 0)
                    retValue = true;
                if (current.articoloSostituzioni.flagSostituito)
                    retValue = true;
            }
            retValue = true;
            return retValue;
        }

        private void grdhome_MouseUp(object sender, MouseButtonEventArgs e)
        {
            exitPage();
        }

        private void grdCanc_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (txtCode.Text.Length > 0)
                txtCode.Text = txtCode.Text.Substring(0, txtCode.Text.Length - 1);
        }

        private void grdCancel_MouseUp(object sender, MouseButtonEventArgs e)
        {
            exitPage();
        }

        private void lblBack_MouseUp(object sender, MouseButtonEventArgs e)
        {
            exitPage();
        }

        private void lblAnnulla_MouseUp(object sender, MouseButtonEventArgs e)
        {
            exitPage();
        }

        private void grdClose_MouseUp(object sender, MouseButtonEventArgs e)
        {
            grdNotFound.Visibility = System.Windows.Visibility.Hidden;
            nfMessage.Text = "NUMERO ORDINE\nO NUMERO CARTA FEDELTA'\nNON RICONOSCIUTO.";
            grdHelpPopUp.Visibility = System.Windows.Visibility.Hidden;
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            UIElement parent = App.Current.MainWindow;
            parentWindow = (MainPage)parent;
            parent = null;
            parentWindow.logMsg("LeggiCodice_Loaded");

            imgRP.Source = parentWindow.rp.signImg;

            imgRP.Width = parentWindow.rp.signWidth;

            serialPort = new SerialPort(ConfigurationManager.AppSettings["portName"], Convert.ToInt32(ConfigurationManager.AppSettings["baudRate"]), Parity.None, Convert.ToInt32(ConfigurationManager.AppSettings["dataBids"]), StopBits.One);
            serialPort.DataReceived += new SerialDataReceivedEventHandler(LeggiCarta);
            try
            {
                if (!serialPort.IsOpen)
                {
                    serialPort.Open();
                }
                else
                {
                    serialPort.Close();
                    System.Threading.Thread.Sleep(500);
                    serialPort.Open();
                }

            }
            catch { }
            cTimerSec = parentWindow.rp.settings.readCodeTimeout;
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);// TimeSpan.FromSeconds(Convert.ToInt32(ConfigurationManager.AppSettings["timerDaGiocaAHome"]));
            timer.Tick += TimerTick;
            timer.Start();
            txtCode.Focus();
        }

        private void grdHelp_MouseUp(object sender, MouseButtonEventArgs e)
        {
            grdHelpPopUp.Visibility = System.Windows.Visibility.Visible;
        }

        private void callAutoDialer()
        {
            parentWindow.logMsg("Faccio la chiamata all'auto dialer");
            System.Collections.Specialized.NameValueCollection reqparam = new System.Collections.Specialized.NameValueCollection();
            string dateValue = String.Format("{0:yyyy-MM-dd}", DateTime.Now);
            //string PSK = "selexgc" + "xJijhVEwi3_MCmnT_34" + dateValue + "TEST000001";
            string PSK = parentWindow.rp.settings.adUsr + parentWindow.rp.settings.adPwd + dateValue + parentWindow.rp.settings.adCli;
            // byte array representation of that string
            byte[] encodedPSK = new UTF8Encoding().GetBytes(PSK);

            // need MD5 to calculate the hash
            byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPSK);

            // string representation (similar to UNIX format)
            string encoded = BitConverter.ToString(hash)
               .Replace("-", string.Empty)
               .ToLower();

            reqparam.Add("usr", parentWindow.rp.settings.adUsr); // * Login username fornito in fase di attivazione
            reqparam.Add("pwd", encoded); // * MD5( PSK+ usr + aaaa-mm-dd ), PSK è una stringa alfanumerica fornita in fase di attivazione
            //reqparam.Add("cli", "39031778912"); // * Numero chiamante utilizzato per l’instradamento della chiamata.
            reqparam.Add("cli", parentWindow.rp.cli); // * Numero chiamante utilizzato per l’instradamento della chiamata.
            
            //L’elenco dei CLI utilizzabili è fornito in fase di attivazione

            reqparam.Add("cd1", parentWindow.rp.adCd1);
            reqparam.Add("cd2", parentWindow.rp.adCd2); //Questo numero verrà chiamato sono a fronte di una mancata risposta del numero principale

            reqparam.Add("audiofile", parentWindow.rp.adAudiofile); // * Identificativo del file audio da riprodurre, L’elenco dei file audio è fornito in fase di attivazione
            //reqparam.Add("reqID", ""); // Identificativo interno attribuito dal cliente alla richiesta (utile per log e debug)
            string result = "";
            result = parentWindow.sl.autodialer(reqparam);
            //parentWindow.logMsg("Chiamata all'autodialer effettuata: " + result);
            parentWindow.logMsg("Chiamata all'autodialer effettuata");
        }
    }
}
