using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using AllDecNet;

namespace DecNet
{
    public partial class Form1 : Form
    {
      const int MaxRowCount = 5000;
      const int MaxColCount = 8000;
        private Bitmap Picture;
        private Image SourcePicture = null;

        private EncodingInfo[] Info;
        private int CodePage;

        private Total_Decoder Decoder;
        const int maxoptcount = 10;
        int optcnt = 0;
        struct elem
        {
            public Char symbology; // 'L' || 'D' || 'Q'
            public int  next;
        };

        elem[] List;
        int  StartList;
        int  firstpos;
        bool newlist = true;
        IntPtr[] DecO;
        IntPtr[] dupDecO;
        long time;

        char cursymbology;
        TQR_Info FQRInfo;
        TDM_Info FDMInfo;
        TL_Info FLInfo;
        TPDF_Info FPDFInfo;
        TAZ_Info FAZInfo;

        public void InitItems()
        {
          //Decoder

            List = new elem[maxoptcount];
            StartList = 0;
            checkedLB.SetItemChecked(0, true); // regular 1d
            checkedLB.SetItemChecked(1, true); // GS1 1D
            checkedLB.SetItemChecked(2, false); // PostNet
            checkedLB.SetItemChecked(3, false); // IMB
            checkedLB.SetItemChecked(4, false); // NZP
            checkedLB.SetItemChecked(5, false); // SwissPost
            checkedLB.SetItemChecked(6, true); // DM
            checkedLB.SetItemChecked(7, true); // QR Code
            checkedLB.SetItemChecked(8, false); // PDF417
            checkedLB.SetItemChecked(9, true); // Aztec
        }
        public void InitList()
        {
            int prepos  = -1;
            int lastpos = -1;
            int pos;
            int i;

          if (Decoder==null)
            return;
          if (newlist)
          {
              List[0].symbology = 'L';
              List[1].symbology = 'L';
              List[2].symbology = 'L';
              List[3].symbology = 'L';
              List[4].symbology = 'L';
              List[5].symbology = 'L';
              List[6].symbology = 'D';
              List[7].symbology = 'Q';
              List[8].symbology = 'P';
              List[9].symbology = 'A';

              List[0].next = 6;
              List[6].next = 7;
              List[7].next = 1;
              List[1].next = 2;
              List[2].next = 3;
              List[3].next = 4;
              List[4].next = 5;
              List[5].next = 8;
              List[8].next = 9;
              List[9].next = maxoptcount;
              //prepos = 
              pos = 0;
              optcnt = 0;
              firstpos = -1;

              for (i = 0; i < maxoptcount; i++)
              {
                  DecO[i] = IntPtr.Zero;
              }

              for (i = 0; i < maxoptcount; i++)
              {
                  if (checkedLB.GetItemChecked(pos))
                  {
                      if (firstpos < 0)
                      {
                          firstpos = pos;
                          StartList = firstpos; // new start of List
                      }
                      if (prepos >= 0)
                          List[prepos].next = pos;// List[pos].next; ;
                      prepos = lastpos = pos;
                      optcnt++;
                      switch (pos)
                      {
                          case 0:
                              if (dupDecO[0].Equals(IntPtr.Zero))
                                  dupDecO[0] = Decoder.CreateL_Opt(-1, 3); // codetype = all. color = default
                              DecO[0] = dupDecO[0];
                              break;
                          case 1:
                              if (dupDecO[1].Equals(IntPtr.Zero))
                                  dupDecO[1] = Decoder.CreateL_Opt(0x380000, 3); // codetype = TCM_RSS_ALL
                              DecO[1] = dupDecO[1];
                              break;
                          case 2:
                              if (dupDecO[2].Equals(IntPtr.Zero))
                                  dupDecO[2] = Decoder.CreateL_Opt(8, 1); // codetype = PN. color = Black
                              DecO[2] = dupDecO[2];
                              break;
                          case 3:
                              if (dupDecO[3].Equals(IntPtr.Zero))
                                  dupDecO[3] = Decoder.CreateL_Opt(9, 1); // codetype = IMB. color = Black
                              DecO[3] = dupDecO[3];
                              break;
                          case 4:
                              if (dupDecO[4].Equals(IntPtr.Zero))
                                  dupDecO[4] = Decoder.CreateL_Opt(18, 2); // codetype = NZP. color = White
                              DecO[4] = dupDecO[4];
                              break;
                          case 5:
                              if (dupDecO[5].Equals(IntPtr.Zero))
                                  dupDecO[5] = Decoder.CreateL_Opt(19, 2); // codetype = SP. color = White
                              DecO[5] = dupDecO[5];
                              break;
                          case 6:
                              if (dupDecO[6].Equals(IntPtr.Zero))
                                  dupDecO[6] = Decoder.CreateDM_Opt(); 
                              DecO[6] = dupDecO[6];
                              break;
                          case 7:
                              if (dupDecO[7].Equals(IntPtr.Zero))
                                  dupDecO[7] = Decoder.CreateQR_Opt(); 
                              DecO[7] = dupDecO[7];
                              break;
                          case 8:
                              if (dupDecO[8].Equals(IntPtr.Zero))
                                  dupDecO[8] = Decoder.CreatePDF_Opt();
                              DecO[8] = dupDecO[8];
                              break;
                          case 9:
                              if (dupDecO[9].Equals(IntPtr.Zero))
                                dupDecO[9] = Decoder.CreateAZ_Opt();
                              DecO[9] = dupDecO[9];
                              break;
                      }

                  }

                  pos = List[pos].next;
                  if (pos >= maxoptcount)
                      break;
              }
              if (lastpos >= 0)
              {
                  List[lastpos].next = maxoptcount;
              }
              newlist = false;
          }
        }

        int reorderlist(int start, int pos, int count)
        // assign start of list to current pos
        // returns new start
        {
            int i;
            int curpos = start;

            if (count <= 1 || pos == start)
                return start;

            for (i = 0; i < count; i++)
            {
                if (List[curpos].next == pos)
                {
                    List[curpos].next = List[pos].next;
                    List[pos].next = start;
                    start = pos;
                    break;
                }
                else
                {
                    curpos = List[curpos].next;
                }
                if (curpos == maxoptcount)
                    break;
            }
            return start;
        }

        private void InitializeCodePages()
        {
            Info = Encoding.GetEncodings();
            for (int i = 0; i < Info.Length; i++)
            {
                String S;
                Encoding E = Console.Out.Encoding;
                int CP = Info[i].CodePage;
                S = CP.ToString() + " - " + Info[i].DisplayName;
                comboBox1.Items.Add(S);
//                if (E.CodePage == CP)
                if (CP == 1252)
                {
                    comboBox1.SelectedIndex = i;
                    CodePage = CP;
                }
            }
        }

        public Form1()
        {
            IntPtr decptr = IntPtr.Zero;
            InitializeComponent();
            InitializeCodePages();
            
            InitItems();
            Decoder = new Total_Decoder(MaxRowCount, MaxColCount);
            DecO = new IntPtr[maxoptcount];
            dupDecO = new IntPtr[maxoptcount];
        }

        private void Clear()
        {
            if (SourcePicture != null)
                SourcePicture.Dispose();
            richTB.Text = "";
            TypeCodeL.Text = "-";
            if (Picture != null)
               Picture.Dispose();
            Picture = null;
        }

        private void CopyPicture()
        {
            Bitmap B = new Bitmap(SourcePicture);
            Rectangle Re = new Rectangle(0, 0, B.Width, B.Height);
            Picture = B.Clone(Re, PixelFormat.Format24bppRgb);
            Img.Image = Picture;
            B.Dispose();
        }

        private void BnLoad_Click(object sender, EventArgs e)
        {
            Clear();
            DialogResult R = OpenDialog.ShowDialog();
            if (R == DialogResult.OK)
            {
                SourcePicture = Image.FromFile(OpenDialog.FileName);
                CopyPicture();
                LabelFileName.Text = OpenDialog.FileName;
                BnDecode.Enabled = true;
            }
            //InitializeCodePages();

        }

        private void BnDecode_Click(object sender, EventArgs e)
        {
            DateTimeOffset dto;
            int ms = 0;
            int s = 0;
            int h, m;

            dto = DateTimeOffset.Now;
            h = dto.Hour;
            m = dto.Minute;
            s = dto.Second;
            ms = dto.Millisecond;

            Decode_Image(Picture);

            dto = DateTimeOffset.Now;
            h = dto.Hour - h;
            m = dto.Minute - m;
            s = dto.Second - s;
            ms = dto.Millisecond - ms;

            if (((h * 12 + m) * 60 + s) < 0)
                h = m = s = ms = 0;
            TimeEdit.Text = (((h * 12 + m) * 60 + s) * 1000 + ms).ToString();

            BnDecode.Enabled = false;
        }

        private void DrawCorners(int RejectR, TRowCols RowCols)
        {
            if (Picture == null) return;
            float X1, X2, Y1, Y2;
            int I1, I2, I;
            Pen P;
            float wid = Picture.Width / 600 + 3;
            if (RejectR == 0)
            {
                P = new Pen(Color.Lime, wid);
                Graphics G = Graphics.FromImage(Picture);
                for (I = 0; I < 4; I++)
                {
                    I1 = (I * 2 + 0);
                    I2 = (I * 2 + 2);
                    if (I2 > 7) I2 = 0;
                    X1 = (float)RowCols[I1 + 1];
                    Y1 = (float)RowCols[I1 + 0];
                    X2 = (float)RowCols[I2 + 1];
                    Y2 = (float)RowCols[I2 + 0];
                    G.DrawLine(P, X1, Y1, X2, Y2);
                }

                Img.Image = Picture;
            }
        }

        public void Decode_Image(Bitmap BMP)
        {
          int q; // == count of decoded codes
          int cnt;
          int pos;

          InitList(); 
          pos = StartList;
          cursymbology = ' ';
          for (cnt = 0; cnt <= optcnt; cnt++)
          {
              if (List[pos].symbology == 'L')
              {
                  if (DecO[pos].Equals(IntPtr.Zero))
                      q = 0;
                  else
                      q = Decoder.DecL_Image(DecO[pos], BMP);
                  if (q > 0)
                  {
                      //TL_Info FLInfo;
                      //string str;
                      cursymbology = 'L';
                      FLInfo = Decoder.Get_L_Info(0);
                      //str = FLInfo.GetDecodedChars();
                      //richTB.Text = str;
                      richTB.Text = FLInfo.GetDecodedChars(CodePage);
                      DrawCorners(Decoder.FRejectionReason, FLInfo.RowCols);
                      TypeCodeL.Text = FLInfo.GetTypecode();

                      StartList = reorderlist(StartList, pos, optcnt);
                      return;
                  }
                  else
                  {
                      pos = List[pos].next;
                  }
              }else if(List[pos].symbology == 'Q')
              {
                  if (DecO[pos].Equals(IntPtr.Zero))
                      q = 0;
                  else
                      q = Decoder.DecQR_Image(DecO[pos], BMP);
                  if (q > 0)
                  {
                      cursymbology = 'Q';
                      FQRInfo = Decoder.Get_QR_Info(0);
                      richTB.Text = FQRInfo.QR_GetDecodedChars();
                      DrawCorners(Decoder.FRejectionReason, FQRInfo.RowCols);
                      TypeCodeL.Text = "QR Code";

                      StartList = reorderlist(StartList, pos, optcnt);
                     return;
                  }
                  else
                  {
                      pos = List[pos].next;
                  }
              }
              else if (List[pos].symbology == 'D')
              {
                  if (DecO[pos].Equals(IntPtr.Zero))
                      q = 0;
                  else
                      q = Decoder.DecDM_Image(DecO[pos], BMP);
                  if (q > 0)
                  {
                      cursymbology = 'D';
                      //TDM_Info FDMInfo;
                      FDMInfo = Decoder.Get_DM_Info(0);
                      richTB.Text = FDMInfo.GetDecodedChars(CodePage);
                      DrawCorners(Decoder.FRejectionReason, FDMInfo.RowCols);
                      TypeCodeL.Text = "Data Matrix";

                      StartList = reorderlist(StartList, pos, optcnt);
                      return;
                  }
                  else
                  {
                      pos = List[pos].next;
                  }
              }
              else if (List[pos].symbology == 'P')
              {
                  if (DecO[pos].Equals(IntPtr.Zero))
                      q = 0;
                  else
                      q = Decoder.DecPDF_Image(DecO[pos], BMP);
                  if (q > 0)
                  {
                      cursymbology = 'P';
                      FPDFInfo = Decoder.Get_PDF_Info(0);
                      richTB.Text = FPDFInfo.GetDecodedChars(CodePage);
                      DrawCorners(Decoder.FRejectionReason, FPDFInfo.RowCols);
                      TypeCodeL.Text = "PDF417";

                      StartList = reorderlist(StartList, pos, optcnt);
                      return;
                  }
                  else
                  {
                      pos = List[pos].next;
                  }
              }
              else if (List[pos].symbology == 'A')
              {
                if (DecO[pos].Equals(IntPtr.Zero))
                  q = 0;
                else
                  q = Decoder.DecAZ_Image(BMP);
                if (q > 0)
                {
                  cursymbology = 'A';
                  FAZInfo = Decoder.Get_AZ_Info(0);
                  richTB.Text = FAZInfo.GetDecodedChars(CodePage);
                  DrawCorners(Decoder.FRejectionReason, FAZInfo.RowCols);
                  TypeCodeL.Text = "Aztec";

                  StartList = reorderlist(StartList, pos, optcnt);
                  return;
                }
                else
                {
                  pos = List[pos].next;
                }
              }
              else
              {
                  pos = List[pos].next;
              }
              if (pos >= maxoptcount)
                  break;
          }
        }

        private void checkedLB_SelectedIndexChanged(object sender, EventArgs e)
        {
            newlist = true;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            int Index = comboBox1.SelectedIndex;
            CodePage = Info[Index].CodePage;
            //richTB.Clear(); // Refresh();
            if (cursymbology == 'D')
                richTB.Text = FDMInfo.GetDecodedChars(CodePage);
            else if (cursymbology == 'L')
                richTB.Text = FLInfo.GetDecodedChars(CodePage);
            else if (cursymbology == 'Q')
                richTB.Text = FQRInfo.QR_GetDecodedChars();
            else
                richTB.Clear();
        }


    }
}
