using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using icLDecNetPro;

namespace Sharp_LC_PRO
{
    public partial class Form1 : Form
    {
        private Bitmap Picture;
        private Image SourcePicture=null;
        private EncodingInfo[ ] Info;
        private int CodePage;
        private icLC_Decoder_Pro Decoder = null;
        private TL_Info FL_Info=null;
        int LCount;

        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 )
                {
                    comboBox1.SelectedIndex = i;
                    CodePage = CP;
                }
            }
        }
        public Form1 (IntPtr decptr)
        {
            Decoder = new icLC_Decoder_Pro(decptr);

            InitializeComponent( );
            InitializeCodePages( );

            ModeToForm( );

            comboBox2.SelectedIndex = 0;
        }
//        #region ModeToForm
        private void MaxLCountToForm ( )
        {
            MaxLCountEdit.Value = Decoder.MaxLCount;
        }

        private void ModeToForm ( )
        {
            MaxLCountToForm( );
            TypeCodeCB.SelectedIndex = 0;
            QualityComboBox.SelectedIndex = 1;
            ColorCB.SelectedIndex = 2; // L_Default
        }

//        #endregion


//        #region FormToMode

        private void FormToMaxLCount ( )
        {
            Decoder.MaxLCount = (int)MaxLCountEdit.Value;
        }

        private void FormToTypeCode ( )
        {
            switch (TypeCodeCB.SelectedIndex)
            {
                case 0: Decoder.codeType = -1; break;  // tcm_all
                case 1: Decoder.codeType = 1; break;   // Code128
                case 2: Decoder.codeType = 2; break;   // code39
                case 3: Decoder.codeType = 3; break;
                case 4: Decoder.codeType = 4; break;
                case 5: Decoder.codeType = 5; break;
                case 6: Decoder.codeType = 6; break;
                case 7: Decoder.codeType = 7; break;
                case 8: Decoder.codeType = 14; break;  // EAN13 Ex
                case 9: Decoder.codeType = 15; break;  // UPCE Ex
                case 10: Decoder.codeType = 8; break;  // Postnet
                case 11: Decoder.codeType = 9; break;  // IMB
                case 12: Decoder.codeType = 17; break; // TADF
                case 13: Decoder.codeType = 18; break; // NZP
                case 14: Decoder.codeType = (int)TYPE_CODE.TC_TEAN13; break; // UPCA. Decoded as EAN13.
                case 15: Decoder.codeType = 10; break; // Pharma
                case 16: Decoder.codeType = 11; break; // RSS
                case 17: Decoder.codeType = 12; break; // RSS_L
                case 18: Decoder.codeType = 13; break; // RSS_E
                case 19: Decoder.codeType = 0x380000; break; // RSS_All
                case 20: Decoder.codeType = (int)TYPE_CODE.TC_TCODE93; break;
                default: Decoder.codeType = -1; break;
            }
        }

        private void FormToParamq()
        {
            Decoder.paramq = (int)QualityComboBox.SelectedIndex;
        }

        private void FormToColor()
        {
            switch (ColorCB.SelectedIndex)
            {
                case 0 : Decoder.L_Color = 1; break;  // L_Black
                case 1 : Decoder.L_Color = 2; break;  // L_White
                case 2 : Decoder.L_Color = 3; break;  // L_Default
                default: Decoder.L_Color = 3; break;  // L_Default
            }
        }

        private void FormToScanStep()
        {
           Decoder.ScanStep = (int)scanStep.Value;
        }

        private void FormToDecodeMode()
        {
         Decoder.SetMode((L_Mode)comboBox2.SelectedIndex);   
        }

        private void FormToMode()
        {
            FormToMaxLCount();
            FormToTypeCode();
            FormToParamq();
            FormToColor();
            FormToScanStep();
            FormToDecodeMode();
        }

//        #endregion

        private void Clear ( )
        {
            TimeEdit.Text = "";
            CountEdit.Text = "";
            rrEdit.Text = "";
            SymbolNumber.Value = 0;
            SymbolNumber.Maximum = 0;
            SymbolNumber.Enabled = false;
            FL_Info = null;
            //vvvvvvvvvvvvvvvvvvvv
            if (SourcePicture!=null)
              SourcePicture.Dispose();
            //vvvvvvvvvvvvvvvvvvvv
        }
        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;
        }

        private void DrawCorners (bool Ok, TRowCols RowCols)
        {
            if ( Picture == null ) return;
            float X1, X2, Y1, Y2;
            int I1, I2, I;
            Pen P;
            float wid = Picture.Width/600+3;
            if ( Ok )
                P = new Pen( Color.Lime,wid);
            else
                P = new Pen(Color.Red, 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;
        }

        unsafe public void DrawSL()
//        public void DrawSL()
        {
            if (Picture == null) return;
            float X1, X2, Y1, Y2;
            int I, j;
            Pen P;
            float wid = Picture.Width / 600 + 1;

            TL_Info.LINEAR_SCAN_LINE sl;

            Graphics G = Graphics.FromImage(Picture);

            for (j = 1; j <= 10; j++)
            {
                switch(j){
                    case 1: sl = FL_Info.FInfo->sl1; break;
                    case 2: sl = FL_Info.FInfo->sl2; break;
                    case 3: sl = FL_Info.FInfo->sl3; break;
                    case 4: sl = FL_Info.FInfo->sl4; break;
                    case 5: sl = FL_Info.FInfo->sl5; break;
                    case 6: sl = FL_Info.FInfo->sl6; break;
                    case 7: sl = FL_Info.FInfo->sl7; break;
                    case 8: sl = FL_Info.FInfo->sl8; break;
                    case 9: sl = FL_Info.FInfo->sl9; break;
                    case 10: sl = FL_Info.FInfo->sl10; break;
                    default: return;
                };
                for (I = 0; I < 4; I++)
                {
                    X1 = (float)sl.scan_line_start_x;
                    Y1 = (float)sl.scan_line_start_y;
                    X2 = (float)sl.scan_line_end_x;
                    Y2 = (float)sl.scan_line_end_y;
                    wid = Picture.Width / 600 + 1+2*sl.first;
                    P = new Pen(Color.Yellow, wid);
                    G.DrawLine(P, X1, Y1, X2, Y2);
                }
            }

            Img.Image = Picture;
        }

        unsafe private void button2_Click (object sender, EventArgs e)
        {
            // Set addition options
            Decoder.SetExtendUPCE_to_UPCA(ExtendUPCE_to_UPCA.Checked);

            DateTimeOffset dto;
            int ms = 0;
            int s = 0;
            int h, m;
           
            FormToMode();
            button2.Enabled = false;

            dto = DateTimeOffset.Now;
            ms = dto.Millisecond;
            h = dto.Hour;
            m = dto.Minute;
            s = dto.Second;
            
            Decoder.DecodeImage( 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();
/*
            if (Decoder.Rejection_Reason.ToString() == "L_SUCCESSFUL")
                rrEdit.Text = "OK";
            else
                rrEdit.Text = "1D Code not Found";
*/
            LCount = Decoder.LCount;
            CountEdit.Text = LCount.ToString( );

            if (LCount > 0)
            {
                SymbolNumber.Enabled = true;
                SymbolNumber.Maximum = LCount - 1;
                ShowInfo(0);
            }
            else {
                rrEdit.Text = Decoder.Rejection_Reason.ToString(); // "LCOUNT = 0 !";
            }

            SymbolNumber.Focus();

        }

        public void ClearForm()
        {
            LCount = 0;
            TB_SymbologyID.Text = "";
            TB_Typecode.Text = "";
            RSErrTextBox.Text = "";

            textBox1.Text = "";
            TB_symbol_contrast.Text = "";
            TB_symbol_contrast_grade.Text = "";
            TB_decode.Text = "";
            TB_decode_grade.Text = "";
            TB_rmax.Text = "";
            TB_rmin.Text = "";
            TB_rming.Text = "";
            TB_ecmin.Text = "";
            TB_ecming.Text = "";
            TB_def.Text = "";
            TB_defg.Text = "";
            TB_decty.Text = "";
            TB_dectyg.Text = "";

//            TB_unused_error_correction_grade.Text = "";
            TB_modulation_grade.Text = "";
            TB_overall_grade.Text = "";
        }
        private void button1_Click(object sender, EventArgs e)
        {
            ClearForm();
            Clear( );
            DialogResult R = OpenDialog.ShowDialog( );
            if ( R == DialogResult.OK )
            {
                SourcePicture = Image.FromFile( OpenDialog.FileName );
                CopyPicture( );
                LabelFileName.Text = OpenDialog.FileName;
                button2.Enabled = true;
            }

        }

        private void ShowInfo (int Index)
        {
            FL_Info = Decoder.Get_L_Info( Index );
            CopyPicture( );
            for ( int i = 0; i < Decoder.LCount; i++ )
            {
                TL_Info iInfo = Decoder.Get_L_Info( i );
                TRowCols RC = iInfo.RowCols;
                bool Ok = (i==Index); // && (iInfo.RSErr>=0);
                DrawCorners( Ok, RC );
                DrawSL();
            }
            InfoToForm( );
        }
        String QValue (float V)
        {
            if (V < 0) return "";
            return V.ToString("0.00");
        }
        String QGrade (float V)
        {
            if ( V < 0 ) return "";
            return V.ToString(  );
        }
        unsafe private void InfoToForm ( )
        {
            if ( FL_Info == null )
            {
                ClearForm();
                rrEdit.Text = "?";
            }
            else
            {
                String SymbologyID;
                String[] no_yes = { "No", "Yes" };

                SymbologyID = FL_Info.GetSymbologyID();
                TB_SymbologyID.Text = SymbologyID;

                TB_Typecode.Text = FL_Info.GetTypecode(FL_Info.FInfo->type);

                textBox1.Text = FL_Info.GetDecodedChars(CodePage);
                RSErrTextBox.Text = FL_Info.RSErr.ToString( );

                TL_Quality Q = FL_Info.Quality;

                TB_symbol_contrast.Text = QValue( Q.symbol_contrast );
                TB_decode.Text = QValue( Q.decode );
                TB_ecmin.Text = QValue(Q.min_edge_contrast);
                TB_rmin.Text = QValue(Q.min_reflectance);
                TB_rmax.Text = QValue(Q.max_reflectance);
                TB_def.Text = QValue(Q.defects);
                TB_decty.Text = QValue(Q.decodability);

                TB_symbol_contrast_grade.Text = QGrade( Q.symbol_contrast_grade );
                TB_ecming.Text = QGrade(Q.min_edge_contrast_grade);
                TB_rming.Text = QGrade(Q.min_reflectance_grade);
                TB_defg.Text = QGrade(Q.defects_grade);
                TB_modulation_grade.Text = QGrade( Q.modulation_grade );
                TB_decode_grade.Text = QGrade( Q.decode_grade );
                TB_dectyg.Text = QGrade(Q.decodability_grade);
                TB_overall_grade.Text = QGrade(Q.overall_grade);

                //rrEdit.Text = FL_Info.FInfo->RejectionReason.ToString();
                int rr;
                rr = FL_Info.FInfo->RejectionReason;
                switch (rr) { 
                    case (int)L_REJECTION_REASON.L_SUCCESSFUL     : rrEdit.Text = "OK"; break;
                    case (int)L_REJECTION_REASON.L_NO_LINEAR_FOUND: rrEdit.Text = "NO_LINEAR_FOUND"; break;
                    case (int)L_REJECTION_REASON.L_POOR_IMAGE_QUALITY: rrEdit.Text = "POOR_IMAGE_QUALITY"; break;
                    case (int)L_REJECTION_REASON.L_RR_UNKNOWN: rrEdit.Text = "RR_UNKNOWN"; break;
                    case (int)L_REJECTION_REASON.L_RS_ERROR       : rrEdit.Text = "RS_ERROR"; break; // in NZP
                    case (int)L_REJECTION_REASON.L_CHECKSUM_FAILED: rrEdit.Text = "CHECKSUM_FAILED"; break;
                    case (int)L_REJECTION_REASON.L_NOT_CONFIRMED  : rrEdit.Text = "NOT_CONFIRMED"; break;
                    case (int)L_REJECTION_REASON.L_NOT_QUIET_ZONE : rrEdit.Text = "QUIET_ZONE ERROR"; break; 
                    //UseRSS
                    case (int)L_REJECTION_REASON.L_2D_FAILED      : rrEdit.Text = "2D_FAILED IN RSS"; break;         
                    //!< obligatory 2D-symbol is not found
                    case (int)L_REJECTION_REASON.L_NOT_SUPPORTED  : rrEdit.Text = "SYMBOLOGY NOT SUPPORTED"; break;         
//                    case default : rrEdit.Text = "NO VALIDE IMAGE FOUND"; break;
                }
            }
            
        }
        private void SymbolNumber_ValueChanged (object sender, EventArgs e)
        {
            int Index = (int)SymbolNumber.Value ;
            ShowInfo( Index );
        }

        private void comboBox1_SelectedIndexChanged (object sender, EventArgs e)
        {
            int Index = comboBox1.SelectedIndex;
            CodePage = Info[ Index ].CodePage;
            InfoToForm( );
        }

        private void Img_MouseDown(object sender, MouseEventArgs e)
        {
            int col, row;
            int i, n;
            int i0;
            int s0, s1, s;
            bool confirm;
            int rowcount = Picture.Height;
            int colcount = Picture.Width;
            TL_Info iInfo;
            TRowCols RC;

            int r, w, c, h, dw, dh;
            if (Decoder == null) return;


            c = e.X;
            r = e.Y;
            w = Img.Width;
            h = Img.Height;

            dw = dh = 0;
            if (rowcount * w  > colcount * h){ //w/h > colcount/rowcount => Vertical stretch
                dw = (w-colcount*h/rowcount)/2;
            }
            else if (rowcount * w  < colcount * h) // horizontal stretch
            {
                dh = (h-rowcount*w/colcount)/2;
            }
            if (dw>0)
//                col = (c - dw) * colcount / (colcount*h/rowcount) ;
                col = (c - dw) * rowcount / h;
            else
                col = c * colcount / w;
            if (dh>0)
                row = (r - dh) * colcount / w;
            else
                row = r * rowcount / h;

            i0 = -1;
            s1 = 0x7FFFFFFF;  
            for (i = 0; i < LCount; i++)
            {
                iInfo = Decoder.Get_L_Info(i);
                RC = iInfo.RowCols;
                s0 = (int)((RC[0] - row) * (RC[3] - col) -
                           (RC[1] - col) * (RC[2] - row));
                confirm = true;
                for (n = 1; n < 4; n++)
                {
                    s = (int)((RC[2 * n % 8] - row) * (RC[(2 * n + 3) % 8] - col) -
                        (RC[(2 * n + 1) % 8] - col) * (RC[(2 * n + 2) % 8] - row));
                    if ((s0 > 0) && (s < 0)) confirm = false;
                    if ((s0 < 0) && (s > 0)) confirm = false;
                }
                if (confirm) // point of "mouse down" belongs to rectangle
                {
                    SymbolNumber.Value = i; // change matrix to "i"
                    return;
                }
                for (n = 0; n < 4; n++) // looking for closest corner
                {
                    s = (int)((RC[2 * n] - row) * (RC[2 * n] - row) +
                              (RC[2 * n + 1] - col) * (RC[2 * n + 1] - col));
                    if (s1 > s)
                    {
                        s1 = s;
                        i0 = i;
                    }
                }
            }
            if (i0 >= 0)
            {
                SymbolNumber.Value = i0;
                return;
            }
        }

      private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
      {
         if (comboBox2.SelectedIndex != 0)
         {
            // L_M_SMALL_QZ and L_M_STANDARD_AND_SMALL_QZ support only single symbologes on image
            MaxLCountEdit.Value = 1; 
         }
      }
   }
}