using System;
using System.Data;
using System.Text;
using System.Windows.Forms;
using FastReport.Utils;
using System.Globalization;
using System.Collections.Generic;

namespace FastReport.Data.ConnectionEditors
{
    internal partial class CsvConnectionEditor : ConnectionEditorBase
    {
        #region Constants
        private const int NUMBER_OF_PREVIEW_STRINGS = 7;
        #endregion Constants

        #region Fields

        private Encoding encoding;
        private string separator;
        private bool updating;

        #endregion Fields

        #region Constructors

        public CsvConnectionEditor()
        {
            updating = true;
            InitializeComponent();
            Localize();
            InitCodepagesList();
            InitSeparatorsList();
            InitCultures();
            encoding = Encoding.Default;
            separator = ";";
            updating = false;
        }

        #endregion Constructors

        #region Private Methods

        private void InitCodepagesList()
        {
            MyRes res = new MyRes("ConnectionEditors,Csv,Codepages");
            cbxCodepage.Items.Add(res.Get("Default"));
            cbxCodepage.Items.Add(res.Get("ASCII"));
            cbxCodepage.Items.Add(res.Get("UTF8"));
            cbxCodepage.Items.Add(res.Get("UTF7"));
            cbxCodepage.Items.Add(res.Get("UTF32"));
            cbxCodepage.Items.Add(res.Get("Unicode"));
            cbxCodepage.Items.Add(res.Get("BigEndianUnicode"));
            cbxCodepage.SelectedIndex = 0;
        }

        private void InitSeparatorsList()
        {
            MyRes res = new MyRes("ConnectionEditors,Csv,Separators");
            cbxSeparator.Items.Add(res.Get("Semicolon"));
            cbxSeparator.Items.Add(res.Get("Comma"));
            cbxSeparator.Items.Add(res.Get("Space"));
            cbxSeparator.Items.Add(res.Get("Tab"));
            cbxSeparator.Items.Add(res.Get("Other"));
            cbxSeparator.SelectedIndex = 0;
        }

        private void InitCultures()
        {
            SortedList<string, CultureInfo> cultures = new SortedList<string, CultureInfo>();
            foreach (CultureInfo info in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
            {
                if (!cultures.ContainsKey(info.DisplayName))
                    cultures.Add(info.DisplayName, info);
            }

            List<string> locales = new List<string>();
            locales.Add(CultureInfo.CurrentCulture.Name);
            locales.Add("en-US");
            foreach (CultureInfo info in cultures.Values)
            {
                locales.Add(info.Name);
            }
            
            cbxNumberFormat.Items.AddRange(locales.ToArray());
            cbxCurrencyFormat.Items.AddRange(locales.ToArray());
            cbxDateTimeFormat.Items.AddRange(locales.ToArray());
        }

        private int GetSelectedIndexByEncoding(Encoding encoding)
        {
            if (encoding == Encoding.Default)
            {
                return 0;
            }
            else if (encoding == Encoding.ASCII)
            {
                return 1;
            }
            else if (encoding == Encoding.UTF8)
            {
                return 2;
            }
            else if (encoding == Encoding.UTF7)
            {
                return 3;
            }
            else if (encoding == Encoding.UTF32)
            {
                return 4;
            }
            else if (encoding == Encoding.Unicode)
            {
                return 5;
            }
            else if (encoding == Encoding.BigEndianUnicode)
            {
                return 6;
            }
            return 0;
        }

        private Encoding GetEncodingBySelectedIndex(int index)
        {
            Encoding encoding = Encoding.Default;
            switch (index)
            {
                case 0:
                    encoding = Encoding.Default;
                    break;
                case 1:
                    encoding = Encoding.ASCII;
                    break;
                case 2:
                    encoding = Encoding.UTF8;
                    break;
                case 3:
                    encoding = Encoding.UTF7;
                    break;
                case 4:
                    encoding = Encoding.UTF32;
                    break;
                case 5:
                    encoding = Encoding.Unicode;
                    break;
                case 6:
                    encoding = Encoding.BigEndianUnicode;
                    break;
                default:
                    encoding = Encoding.Default;
                    break;
            }
            return encoding;
        }

        private void SetSeparator(string separator)
        {
            this.separator = separator;
            int index = 4;
            switch (separator)
            {
                case ";":
                    index = 0;
                    break;
                case ",":
                    index = 1;
                    break;
                case " ":
                    index = 2;
                    break;
                case "\t":
                    index = 3;
                    break;
            }
            cbxSeparator.SelectedIndex = index;
            if (index == 4)
            {
                tbSeparator.Enabled = true;
                tbSeparator.Text = separator;
            }

        }

        private void Localize()
        {
            MyRes res = new MyRes("ConnectionEditors,Csv");
            gbSelectDatabase.Text = res.Get("ConfigureDatabase");
            labelSelectCsvFile.Text = res.Get("SelectFile");
            labelCodepage.Text = res.Get("Codepage");
            labelSeparator.Text = res.Get("Separator");
            cbxFieldNames.Text = res.Get("FieldNames");
            cbxRemoveQuotes.Text = res.Get("RemoveQuotes");
            cbxTryConvertTypes.Text = res.Get("ConvertTypes");
            lblNumberFormat.Text = res.Get("NumberFormat");
            lblCurrencyFormat.Text = res.Get("CurrencyFormat");
            lblDateTimeFormat.Text = res.Get("DateTimeFormat");
            tabFilePreview.Text = res.Get("FilePreview");
            tabDataPreview.Text = res.Get("DataPreview");
        }

        public override void UpdateDpiDependencies()
        {
            base.UpdateDpiDependencies();
            tbCsvFile.Image = this.GetImage(1);
            int width = this.LogicalToDevice(400);
            cbxNumberFormat.DropDownWidth = width;
            cbxCurrencyFormat.DropDownWidth = width;
            cbxDateTimeFormat.DropDownWidth = width;
        }

        private void LoadPreview()
        {
            if (updating)
                return;

            CsvConnectionStringBuilder builder = new CsvConnectionStringBuilder(GetConnectionString());
            List<string> rawLines = CsvUtils.ReadLines(builder, NUMBER_OF_PREVIEW_STRINGS);
            DataTable table = CsvUtils.CreateDataTable(builder, rawLines);
            if (table != null)
            {
                for (int i = 0; i < table.Columns.Count; i++)
                {
                    table.Columns[i].ColumnName += " (" + table.Columns[i].DataType.Name + ")";
                }
                
                tbFilePreview.Lines = rawLines.ToArray();
                DataSet ds = new DataSet();
                ds.Tables.Add(table);
                dgvTablePreview.AutoGenerateColumns = true;
                dgvTablePreview.DataSource = ds;
                dgvTablePreview.Update();
                dgvTablePreview.DataMember = table.TableName;
            }
        }

        #endregion Private Methods

        #region Protected Methods

        protected override string GetConnectionString()
        {
            CsvConnectionStringBuilder builder = new CsvConnectionStringBuilder();
            builder.CsvFile = tbCsvFile.Text;
            builder.Codepage = GetEncodingBySelectedIndex(cbxCodepage.SelectedIndex).CodePage;
            builder.Separator = separator;
            builder.FieldNamesInFirstString = cbxFieldNames.Checked;
            builder.RemoveQuotationMarks = cbxRemoveQuotes.Checked;
            builder.ConvertFieldTypes = cbxTryConvertTypes.Checked;
            builder.NumberFormat = cbxNumberFormat.SelectedItem.ToString();
            builder.CurrencyFormat = cbxCurrencyFormat.SelectedItem.ToString();
            builder.DateTimeFormat = cbxDateTimeFormat.SelectedItem.ToString();
            return builder.ToString();
        }

        protected override void SetConnectionString(string value)
        {
            updating = true;
            CsvConnectionStringBuilder builder = new CsvConnectionStringBuilder(value);
            tbCsvFile.Text = builder.CsvFile;
            cbxCodepage.SelectedIndex = GetSelectedIndexByEncoding(Encoding.GetEncoding(builder.Codepage));
            SetSeparator(builder.Separator);
            cbxFieldNames.Checked = builder.FieldNamesInFirstString;
            cbxRemoveQuotes.Checked = builder.RemoveQuotationMarks;
            cbxTryConvertTypes.Checked = builder.ConvertFieldTypes;
            cbxNumberFormat.SelectedItem = builder.NumberFormat;
            cbxCurrencyFormat.SelectedItem = builder.CurrencyFormat;
            cbxDateTimeFormat.SelectedItem = builder.DateTimeFormat;
            updating = false;
            LoadPreview();
        }

        #endregion Protected Methods

        #region Events Handlers

        private void tbCsvFile_ButtonClick(object sender, EventArgs e)
        {
            using (OpenFileDialog dialog = new OpenFileDialog())
            {
                dialog.Filter = Res.Get("FileFilters,CsvFile") + "|" + Res.Get("FileFilters,TxtFile") + "|" + Res.Get("FileFilters,AllFiles");
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    tbCsvFile.Text = dialog.FileName;
                    LoadPreview();
                }
            }
        }

        private void cbxEncoding_SelectedIndexChanged(object sender, EventArgs e)
        {
            encoding = GetEncodingBySelectedIndex(cbxCodepage.SelectedIndex);
            LoadPreview();
        }

        private void cbxSeparator_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (updating)
                return;
            if (cbxSeparator.SelectedIndex == cbxSeparator.Items.Count - 1)
            {
                tbSeparator.Enabled = true;
                separator = tbSeparator.Text;
            }
            else
            {
                tbSeparator.Enabled = false;
                switch (cbxSeparator.SelectedIndex)
                {
                    case 0:
                        separator = ";";
                        break;
                    case 1:
                        separator = ",";
                        break;
                    case 2:
                        separator = " ";
                        break;
                    case 3:
                        separator = "\t";
                        break;
                    default:
                        separator = ";";
                        break;
                }
            }
            LoadPreview();
        }

        private void tbSeparator_TextChanged(object sender, EventArgs e)
        {
            if (updating)
                return;
            if (cbxSeparator.SelectedIndex == cbxSeparator.Items.Count - 1)
            {
                separator = tbSeparator.Text;
                LoadPreview();
            }
        }

        private void cbxFieldNames_CheckedChanged(object sender, EventArgs e)
        {
            LoadPreview();
        }

        private void cbxRemoveQuotes_CheckedChanged(object sender, EventArgs e)
        {
            LoadPreview();
        }

        private void cbxTryConvertTypes_CheckedChanged(object sender, EventArgs e)
        {
            LoadPreview();
        }

        private void cbxNumberLocale_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadPreview();
        }

        private CultureInfo cbxFormatDrawItem(object sender, DrawItemEventArgs e)
        {
            e.DrawBackground();
            if (e.Index == -1)
                return null;

            bool isDropDown = (e.State & DrawItemState.ComboBoxEdit) == 0;
            string text = (string)((sender as ComboBox).Items[e.Index]);
            CultureInfo culture = CultureInfo.GetCultureInfo(text);
            text = e.Index == 0 ? Res.Get("ConnectionEditors,Csv,Codepages,Default") : (isDropDown ? culture.DisplayName : text);
            TextRenderer.DrawText(e.Graphics, text, Font, e.Bounds.Location, e.ForeColor);
            if (e.Index == 2)
                e.Graphics.DrawLine(System.Drawing.Pens.Black, e.Bounds.X, e.Bounds.Y, e.Bounds.Right, e.Bounds.Y);
            if (isDropDown)
                return culture;
            return null;
        }

        private void cbxNumberFormat_DrawItem(object sender, DrawItemEventArgs e)
        {
            CultureInfo culture = cbxFormatDrawItem(sender, e);
            if (culture != null)
                TextRenderer.DrawText(e.Graphics, String.Format(culture.NumberFormat, "{0:n}", -1234.56f), Font, e.Bounds, e.ForeColor, TextFormatFlags.Right);
        }

        private void cbxCurrencyFormat_DrawItem(object sender, DrawItemEventArgs e)
        {
            CultureInfo culture = cbxFormatDrawItem(sender, e);
            if (culture != null)
                TextRenderer.DrawText(e.Graphics, String.Format(culture.NumberFormat, "{0:c}", -1234.56f), Font, e.Bounds, e.ForeColor, TextFormatFlags.Right);
        }

        private void cbxDateTimeFormat_DrawItem(object sender, DrawItemEventArgs e)
        {
            CultureInfo culture = cbxFormatDrawItem(sender, e);
            if (culture != null)
                TextRenderer.DrawText(e.Graphics, String.Format(culture.DateTimeFormat, "{0:d}", new DateTime(2007, 11, 30)), Font, e.Bounds, e.ForeColor, TextFormatFlags.Right);
        }
        #endregion Events Handlers
    }
}