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 icDMDecNetPro;

namespace Sharp_DM_EP
{
    public partial class Form1 : Form
    {
        private Bitmap Picture;
        private Image SourcePicture=null;
        private EncodingInfo[ ] Info;
        private int CodePage;
        private icDataMatrix_Decoder_Pro Decoder;
        private TDM_Info FDM_Info=null;
        int DMCount;
        private bool apertureChanged = false;

        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 ()
        {
            Decoder = new icDataMatrix_Decoder_Pro(8192, 8192);
            //Decoder.SetApertureSizeInPercents(100);

            InitializeComponent( );
            InitializeCodePages( );

            ModeToForm( );

            QualityComboBox.SelectedIndex = 2;
        }
        #region ModeToForm
        private void MirrorModeToForm ( )
        {
            switch ( Decoder.MirrorMode )
            {
                case DM_MIRROR_MODE.MM_NORMAL: MirrorComboBox.SelectedIndex = 0; break;
                case DM_MIRROR_MODE.MM_MIRROR: MirrorComboBox.SelectedIndex = 1; break;
                case DM_MIRROR_MODE.MM_ANY: MirrorComboBox.SelectedIndex = 2; break;
            }
        }
        private void LabelModeToForm ( )
        {
            switch ( Decoder.LabelMode )
            {
                case DM_LABEL_MODE.LM_STANDARD: LabelComboBox.SelectedIndex = 0; break;
                case DM_LABEL_MODE.LM_DOTPEEN: LabelComboBox.SelectedIndex = 1; break;
                case DM_LABEL_MODE.LM_ST_DOT: LabelComboBox.SelectedIndex = 2; break;
            }
        }

        private void SpeedModeToForm ( )
        {
            switch ( Decoder.SpeedMode )
            {
                case (int)DM_SPEED.DMSP_ULTIMATEPLUS: SpeedComboBox.SelectedIndex = 0; break;
                case (int)DM_SPEED.DMSP_ULTIMATE: SpeedComboBox.SelectedIndex = 1; break;
                case (int)DM_SPEED.DMSP_REGULAR: SpeedComboBox.SelectedIndex = 2; break;
            }
        }

        private void CellColorToForm ( )
        {
            switch ( Decoder.CellColor )
            {
                case DM_CELL_COLOR.CL_BLACKONWHITE: CellColorComboBox.SelectedIndex = 0; break;
                case DM_CELL_COLOR.CL_WHITEONBLACK: CellColorComboBox.SelectedIndex = 1; break;
                case DM_CELL_COLOR.CL_ANY: CellColorComboBox.SelectedIndex = 2; break;
            }
        }

        private void QualityModeToForm ( )
        {
            switch ( Decoder.QualityMask )
            {
            case DM_QUALITY_MASK.DM_QM_NO:
               QualityComboBox.SelectedIndex = 0;
               break;
            case DM_QUALITY_MASK.DM_PQM_ALL_v2:
               QualityComboBox.SelectedIndex = 2;
               break;
            default: QualityComboBox.SelectedIndex = 1;
               break;
            }
        }
        private void MaxDMCountToForm ( )
        {
            MaxDMCountEdit.Value = Decoder.MaxDMCount;
        }
        private void FilterModeToForm ( )
        {
            switch ( Decoder.FilterMode )
            {
               case DM_FILTER_MODE.FM_AUTO: FilterComboBox.SelectedIndex = 0; break;
                case DM_FILTER_MODE.FM_NON: FilterComboBox.SelectedIndex = 1; break;
                case DM_FILTER_MODE.FM_SHARPMASK: FilterComboBox.SelectedIndex = 2; break;
                case DM_FILTER_MODE.FM_BWR: FilterComboBox.SelectedIndex = 3; break;
            }
        }
        private void QzModeToForm()
        {
            switch (Decoder.QzMode)
            {
                case (int)DMQZ_MODE.DMQZ_NORMAL: QzComboBox.SelectedIndex = 0; break;
                case (int)DMQZ_MODE.DMQZ_SMALL: QzComboBox.SelectedIndex = 1; break;
            }
        }

        private void ModeToForm ( )
        {
            MaxDMCountToForm( );
            MirrorModeToForm( );
            LabelModeToForm( );
            SpeedModeToForm( );
            CellColorToForm( );
            QualityModeToForm( );
            FilterModeToForm( );
            QzModeToForm();
        }
        #endregion


        #region FormToMode
        private void FormToMirrorMode ( )
        {
            switch ( MirrorComboBox.SelectedIndex )
            {
                case 0: Decoder.MirrorMode = DM_MIRROR_MODE.MM_NORMAL; break;
                case 1: Decoder.MirrorMode = DM_MIRROR_MODE.MM_MIRROR; break;
                case 2: Decoder.MirrorMode = DM_MIRROR_MODE.MM_ANY; break;
            }
        }
        private void FormToLabelMode ( )
        {
            switch ( LabelComboBox.SelectedIndex )
            {
                case 0: Decoder.LabelMode = DM_LABEL_MODE.LM_STANDARD; break;
                case 1: Decoder.LabelMode = DM_LABEL_MODE.LM_DOTPEEN; break;
                case 2: Decoder.LabelMode = DM_LABEL_MODE.LM_ST_DOT; break;
            }
        }

        private void FormToSpeedMode ( )
        {
            switch ( SpeedComboBox.SelectedIndex )
            {
                case 0: Decoder.SpeedMode = (int)DM_SPEED.DMSP_ULTIMATEPLUS; break;
                case 1: Decoder.SpeedMode = (int)DM_SPEED.DMSP_ULTIMATE; break;
                case 2: Decoder.SpeedMode = (int)DM_SPEED.DMSP_REGULAR; break;
            }
        }

        private void FormToCellColor ( )
        {
            switch ( CellColorComboBox.SelectedIndex )
            {
                case 0: Decoder.CellColor = DM_CELL_COLOR.CL_BLACKONWHITE; break;
                case 1: Decoder.CellColor = DM_CELL_COLOR.CL_WHITEONBLACK; break;
                case 2: Decoder.CellColor = DM_CELL_COLOR.CL_ANY; break;
            }
        }

        private void FormToQualityMode ( )
        {
         switch (QualityComboBox.SelectedIndex)
         {
            case 0:
               Decoder.QualityMask = DM_QUALITY_MASK.DM_QM_NO;
               break;
            case 2:
               Decoder.QualityMask = DM_QUALITY_MASK.DM_PQM_ALL_v2;
               break;
            default: Decoder.QualityMask = DM_QUALITY_MASK.DM_QM_ALL; break;
         }
        }
        private void FormToMaxDMCount ( )
        {
            Decoder.MaxDMCount = (int)MaxDMCountEdit.Value;
        }

        private void FormToFilterMode ( )
        {
            switch ( FilterComboBox.SelectedIndex) 
            {
                case 0: Decoder.FilterMode = DM_FILTER_MODE.FM_AUTO; break;
                case 1: Decoder.FilterMode = DM_FILTER_MODE.FM_NON; break;
                case 2: Decoder.FilterMode = DM_FILTER_MODE.FM_SHARPMASK; break;
                case 3: Decoder.FilterMode = DM_FILTER_MODE.FM_BWR; break;
            }
        }

        private void FormToQzMode()
        {
            switch (QzComboBox.SelectedIndex)
            {
                case 0: Decoder.QzMode = (int)DMQZ_MODE.DMQZ_NORMAL; break;
                case 1: Decoder.QzMode = (int)DMQZ_MODE.DMQZ_SMALL; break;
            }
        }
        
        private void FormToMode ( )
        {
            FormToMaxDMCount( );
            FormToMirrorMode( );
            FormToLabelMode( );
            FormToSpeedMode( );
            FormToCellColor( );
            FormToQualityMode( );
            FormToFilterMode( );
            FormToQzMode( );
            FormToAperture();
        }
        #endregion

        private void FormToAperture()
        {
         if (apertureChanged)
         {
            apertureChanged = false;
            Decoder.SetApertureSizeInPercents((int)aperture.Value);
         }
        }
        
        private void Clear ( )
        {
            TimeEdit.Text = "";
            CountEdit.Text = "";
            rrEdit.Text = "";
            SymbolNumber.Enabled = false;
            SymbolNumber.Value = 0;
            SymbolNumber.Maximum = 0;
            FDM_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;
        }


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

            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_Reasons.ToString() == "DM_RR_OK")
                rrEdit.Text = "OK";
            else if (Decoder.Rejection_Reasons.ToString() == "DM_RR_DISCONNECTED")
                rrEdit.Text = "Decoder Disconnected";
            else if (Decoder.Rejection_Reasons.ToString() == "DM_RR_REEDSOLOMON")
                rrEdit.Text = "Reed Solomon Error";
            else if (Decoder.Rejection_Reasons.ToString() == "DM_RR_BYCRIT")
                rrEdit.Text = "Poor Image Quality";
            else 
                rrEdit.Text = "DM not Found";

            //            rrEdit.Text = Decoder.Rejection_Reasons.ToString( );

            DMCount = Decoder.DMCount;
            CountEdit.Text = DMCount.ToString( );
            
            if ( DMCount > 0 )
            {
                SymbolNumber.Enabled = true;
                SymbolNumber.Maximum = DMCount - 1;
                ShowInfo(0);
            }

            SymbolNumber.Focus();

        }

        public void ClearForm()
        {
            DMCount = 0;
            TB_SymbologyID.Text = "";
            TB_ActColor.Text = "";
            MirroredTextBox.Text = "";
            DotPeenTextBox.Text = "";
            VDimTextBox.Text = "";
            HDimTextBox.Text = "";
            RSErrTextBox.Text = "";

            textBox1.Text = "";
            TB_symbol_contrast.Text = "";
            TB_axial_nonuniformity.Text = "";
            TB_fixed_pattern_damage.Text = "";
            //TB_QZ_damage.Text = "";
            TB_grid_nonuniformity.Text = "";
            TB_unused_error_correction.Text = "";
            TB_vertical_print_growth.Text = "";
            TB_horizontal_print_growth.Text = "";

            TB_symbol_contrast_grade.Text = "";
            TB_axial_nonuniformity_grade.Text = "";
            TB_grid_nonuniformity_grade.Text = "";
            TB_fixed_pattern_damage_grade.Text = "";
            //TB_QZ_damage_grade.Text = "";
            TB_unused_error_correction_grade.Text = "";
            TB_modulation_grade.Text = "";
            TB_decode_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)
        {
            FDM_Info = Decoder.Get_DM_Info( Index );
            CopyPicture( );
            for ( int i = 0; i < Decoder.DMCount; i++ )
            {
                TDM_Info iInfo = Decoder.Get_DM_Info( i );
                TRowCols RC = iInfo.RowCols;
                bool Ok = (i==Index) && (iInfo.RSErr>=0);
                DrawCorners( Ok, RC );
            }
            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(  );
        }
        private void InfoToForm ( )
        {
            if ( FDM_Info == null )
            {
                ClearForm();
            }
            else
            {
                String SymbologyID;
                String[] no_yes = { "No", "Yes" };
                String Clr;

                textBox1.Text = FDM_Info.GetDecodedChars(CodePage);

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

                MirroredTextBox.Text = no_yes[Convert.ToInt32(FDM_Info.Mirrored)]; //.ToString( );
                DotPeenTextBox.Text = no_yes[Convert.ToInt32(FDM_Info.DotPeen)]; //.ToString( );
                if (FDM_Info.ActColor == 0) Clr = "Black";
                else                        Clr = "White";
                TB_ActColor.Text = Clr;
                VDimTextBox.Text = FDM_Info.VDim.ToString( );
                HDimTextBox.Text = FDM_Info.HDim.ToString( );
                RSErrTextBox.Text = FDM_Info.RSErr.ToString( );

                TDM_Quality Q = FDM_Info.Quality;

                TB_symbol_contrast.Text = QValue( Q.symbol_contrast );
                TB_axial_nonuniformity.Text = QValue( Q.axial_nonuniformity );
                TB_fixed_pattern_damage.Text = QValue( Q.fixed_pattern_damage );
                TB_grid_nonuniformity.Text = QValue( Q.grid_nonuniformity );
                TB_unused_error_correction.Text = QValue( Q.unused_error_correction );
                TB_vertical_print_growth.Text = QValue( Q.vertical_print_growth);
                TB_horizontal_print_growth.Text = QValue( Q.horizontal_print_growth);

                TB_symbol_contrast_grade.Text = QGrade( Q.symbol_contrast_grade );
                TB_axial_nonuniformity_grade.Text = QGrade( Q.axial_nonuniformity_grade );
                TB_grid_nonuniformity_grade.Text = QGrade( Q.grid_nonuniformity_grade );
                TB_fixed_pattern_damage_grade.Text = QGrade( Q.fixed_pattern_damage_grade );
                TB_unused_error_correction_grade.Text = QGrade( Q.unused_error_correction_grade );
                TB_modulation_grade.Text = QGrade( Q.modulation_grade );
                TB_decode_grade.Text = QGrade( Q.decode_grade );
                TB_overall_grade.Text = QGrade( Q.overall_grade );

            }
            
        }
        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;
            TDM_Info iInfo;
            TRowCols RC;

            int r, w, c, h, dw, dh;

            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 < DMCount; i++)
            {
                iInfo = Decoder.Get_DM_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 aperture_ValueChanged(object sender, EventArgs e)
      {
         apertureChanged = true;
      }
   }
}