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.Windows.Controls.Primitives;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Windows.Threading;

namespace CSRender
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        //comboBoxのインスタンス
        private ObservableCollection<ComboBoxSet> PagePattern = new ObservableCollection<ComboBoxSet>();
        private ObservableCollection<ComboBoxSet> FilePattern = new ObservableCollection<ComboBoxSet>();
        public MainWindow()
        {
            InitializeComponent();
            
            //ページ入力メニューの設定
            PagePattern.Add((new ComboBoxSet { Id = 1, Item = "全ページ"}));
            PagePattern.Add((new ComboBoxSet { Id = 2, Item = "指定" }));
            PageRange.ItemsSource = PagePattern;

            pageBox.GotFocus += PageBox_GotFocusSelectAll;

            //出力ファイル形式メニューの設定
            FilePattern.Add((new ComboBoxSet { Id = 1, Item = "JPG" }));
            FilePattern.Add((new ComboBoxSet { Id = 2, Item = "JPEG" }));
            FilePattern.Add((new ComboBoxSet { Id = 3, Item = "PNG" }));
            FilePattern.Add((new ComboBoxSet { Id = 4, Item = "TIF" }));
            FilePattern.Add((new ComboBoxSet { Id = 5, Item = "TIFF" }));
            FilePattern.Add((new ComboBoxSet { Id = 6, Item = "GIF" }));
            FilePattern.Add((new ComboBoxSet { Id = 7, Item = "BMP" }));
            FileSelect.ItemsSource = FilePattern;

            //PureVerifyの内部変数(PureVerifyDlg.env)を編集
            EditEnvFile();
            
            //デフォルトに前回の設定値を表示
            ResolutionBox.Value = Properties.Settings.Default.resolutionSetting;
            FileSelect.Text = Properties.Settings.Default.formatSetting;
            PositionBox.Value = Properties.Settings.Default.shiftPixelSetting;
            GradationBox.Value = Properties.Settings.Default.colorMarginSetting;
            SmallDiffBox.Value = Properties.Settings.Default.removePointSetting;
            VisualBox.Value = Properties.Settings.Default.shadingOffSetting;
            workBox.Text = Properties.Settings.Default.workSpaceSetting;
            targetBox.Text = Properties.Settings.Default.targetSetting;
            referenceBox.Text = Properties.Settings.Default.referenceSetting;

            //ドラッグ&ドロップイベントの追加
            targetBox.AddHandler(TextBox.DragOverEvent, new DragEventHandler(textBox_PreviewDragOver), true);
            targetBox.AddHandler(TextBox.DropEvent, new DragEventHandler(TargetBox_Drop), true);
            referenceBox.AddHandler(TextBox.DragOverEvent, new DragEventHandler(textBox_PreviewDragOver), true);
            referenceBox.AddHandler(TextBox.DropEvent, new DragEventHandler(RefBox_Drop), true);
            workBox.AddHandler(TextBox.DragOverEvent, new DragEventHandler(textBox_PreviewDragOver), true);
            workBox.AddHandler(TextBox.DropEvent, new DragEventHandler(WorkBox_Drop), true);
            reportBox.AddHandler(TextBox.DragOverEvent, new DragEventHandler(textBox_PreviewDragOver), true);
            reportBox.AddHandler(TextBox.DropEvent, new DragEventHandler(ReportBox_Drop), true);
        }

        //Closeボタン実行
        private void CloseButton_Click(object sender, RoutedEventArgs e) =>
    Close();

        /// <summary>
        /// 比較ボタンを実行する。
        /// </summary>
        /// <param name="targetBox.Text">選択された対象フォルダ（ファイル）のパス</param>
        /// <param name="mainWindow">アプリケーションのメインウインドウ</param>
        /// <param name="ResultConsole.Text">出力メニューのテキストボックス</param>
        /// <param name="referenceBox.Text">選択されたリファレンスフォルダ（ファイル）のパス</param>
        /// <param name="workBox.Text">選択された作業フォルダのパス</param>
        /// <param name="shiftPixel">位置ズレ許容量のパラメータ</param>
        /// <param name="colorMargin">諧調差許容量のパラメータ</param>
        /// <param name="removePoint">微小差異許容量のパラメータ</param>
        /// <param name="shadingOff">視覚的あいまい量のパラメータ</param>
        /// <param name="pageFlag">ページ範囲を指定するかどうかを示すフラグ</param>
        /// <param name="selectedPage">TIFF変換するページ範囲</param>
        /// <param name="PageRange.Text">検査範囲を選択するプルダウンメニューで選択された内容の文字列</param>
        /// <param name="pageBox.Text">入力されたページを表す文字列</param>
        /// <param name="targetTIFFPath">対象フォルダのTIFF画像を配置するフォルダのパス</param>
        /// <param name="referenseTIFFPath">リファレンスフォルダのTIFF画像を配置するフォルダのパス</param>
        /// <param name="workDir">PureVerify内部の作業フォルダのパス</param>
        /// <param name="PDFName">検版レポートのファイル名</param>
        /// <param name="reportFlag">PureVerify実行の際にレポート名の引数を加えるかどうかを示すフラグ</param>
        /// <param name="pdfReportPath">検版レポートの出力先パス</param>

        private void CompareButtonClick(object sender, RoutedEventArgs e)
        {
            //対象フォルダのpathチェック
            if (!Directory.Exists(targetBox.Text) && !File.Exists(targetBox.Text))
            {
                CustomMsgBox.Show(mainWindow, "指定されたファイルあるいはフォルダが存在しません。" +
                    "\nもう一度設定してください。", "The specified file or folder does not exist", MessageBoxButton.OK, MessageBoxImage.Information);
                ResultConsole.Text += "　指定された対象ファイルあるいはフォルダを発見できませんでした\r\n";
                ResultConsole.Text += "<TIFF変換中止>\r\n";
                ResultConsole.ScrollToEnd();
                Properties.Settings.Default.targetSetting = "";
                Properties.Settings.Default.Save();
                return;
            }

            //リファレンスファイルのpathチェック
            if (!Directory.Exists(referenceBox.Text) && !File.Exists(referenceBox.Text))
            {
                CustomMsgBox.Show(mainWindow, "指定されたリファレンスファイルあるいはフォルダが存在しません。" +
                    "\nもう一度設定してください。", "The specified reference file or folder does not exist", MessageBoxButton.OK, MessageBoxImage.Information);
                ResultConsole.Text += "　指定されたリファレンスファイルあるいはフォルダを発見できませんでした\r\n";
                ResultConsole.Text += "<TIFF変換中止>\r\n";
                ResultConsole.ScrollToEnd();
                Properties.Settings.Default.referenceSetting = "";
                Properties.Settings.Default.Save();
                return;
            }

            //出力ファイルpathのチェック
            if (!Directory.Exists(workBox.Text) && !File.Exists(workBox.Text))
            {
                CustomMsgBox.Show(mainWindow, "指定された作業フォルダが存在しません。" +
                    "\nもう一度設定してください。", "The work space folder does not exist", MessageBoxButton.OK, MessageBoxImage.Information);
                ResultConsole.Text += "　指定された作業フォルダを発見できませんでした\r\n";
                ResultConsole.Text += "<TIFF変換中止>\r\n";
                ResultConsole.ScrollToEnd();
                workBox.Text = "";
                Properties.Settings.Default.workSpaceSetting = workBox.Text;
                Properties.Settings.Default.Save();
                return;
            }
            string workLogPath = System.IO.Path.Combine(workBox.Text, "report");

            bool reportFlag = false;
            try
            {
                //検版レポートの入力チェック
                reportFlag = checkReportPath();
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message + "\r\nレポート名を初期化しました。", "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：レポート名の確認" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                reportBox.Text = "";
                //referenceErrorFlag = true;
            }
            
            //検版パラメータの取得
            string shiftPixel = PositionBox.Text;
            string colorMargin = GradationBox.Text;
            string removePoint = SmallDiffBox.Text;
            string shadingOff = VisualBox.Text;

            //RIP処理時間の計測
            var ripTime = new System.Diagnostics.Stopwatch();
            ripTime.Start();//計測開始

            //必要に応じてページ引数を指定
            bool pageFlag = false;
            string selectedPage = "";
            if (PageRange.Text == "指定")
            {
                pageFlag = true;
                selectedPage = pageBox.Text;
            }

            //TIFF画像の生成
            ResultConsole.Text += "<TIFF変換開始>\r\n";
            ResultConsole.Text += "　対象ファイルをTIFF画像に変換中\r\n";
            ResultConsole.ScrollToEnd();
            DoEvents();
            
            //対象フォルダ
            string targetTIFFPath = System.IO.Path.Combine(workBox.Text, "work", "targetTIFF");
            if (Directory.Exists(targetTIFFPath))//指定先にTIFF用フォルダがあるか
            {
                Directory.Delete(targetTIFFPath, true);//あれば古いTIFF用フォルダを削除（前回作業時の生成物との混同防止）
            }
            Directory.CreateDirectory(targetTIFFPath);//新規でTIFF用フォルダを作成

            //CSRenderの実行
            try
            {
                string targetTIFFResult =
                OutputTIFF.runCSRender(ResolutionBox.Text, "TIFF", pageFlag, selectedPage, targetBox.Text, targetTIFFPath);
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message, "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：対象PDFのTIFF画像生成" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                //referenceErrorFlag = true;
            }

            ResultConsole.Text += "　リファレンスファイルをTIFF画像に変換中\r\n";
            ResultConsole.ScrollToEnd();
            DoEvents();

            //リファレンスフォルダ
            string referenceTIFFPath = System.IO.Path.Combine(workBox.Text, "work", "referenceTIFF");
            if (Directory.Exists(referenceTIFFPath))//指定先にTIFF用フォルダがあるか
            {
                Directory.Delete(referenceTIFFPath, true);//あれば古いTIFF用フォルダを削除（前回作業時の生成物との混同防止）
            }
            Directory.CreateDirectory(referenceTIFFPath);//新規でTIFF用フォルダを作成

            //CSRenderの実行
            try
            {
                string referenceTIFFResult =
                OutputTIFF.runCSRender(ResolutionBox.Text, "TIFF", pageFlag, selectedPage, referenceBox.Text, referenceTIFFPath);
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message, "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：リファレンスPDFのTIFF画像生成" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                //referenceErrorFlag = true;
            }

            ripTime.Stop();//RIP時間の計測終了
            TimeSpan timeResult = ripTime.Elapsed;
            var allRipTime = $"{timeResult}".Substring(0,8);

            ResultConsole.Text += "　[RIP処理時間　" + allRipTime + "]\r\n";
            ResultConsole.Text += "<TIFF変換完了>\r\n\r\n";
            ResultConsole.ScrollToEnd();
            DoEvents();

            string workDir = "";
            try
            {
                //PureVerifyの実行
                workDir = CompareTIFF.runPureVerify(targetTIFFPath, referenceTIFFPath, workBox.Text
                    , shiftPixel, colorMargin, removePoint, shadingOff, reportFlag, reportBox.Text);
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message, "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：検版処理" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                //referenceErrorFlag = true;
            }

            try
            {
                //レポートを出力
                outputLog(System.IO.Path.Combine(workDir, "report"));
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message, "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：検版ログの出力" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                //referenceErrorFlag = true;
            }

            string PDFName = "";
            try
            {
                //レポート名を取得
                if (reportBox.Text != "")
                {
                    PDFName = reportBox.Text;
                }
                else
                {
                    PDFName = CompareTIFF.getReportName(workDir);
                }
            }
            catch (Exception ex)
            {
                CustomMsgBox.Show(mainWindow, ex.Message, "例外が発生しました", MessageBoxButton.OK, MessageBoxImage.Warning);
                //ログ記述
                DateTime faileTIme = DateTime.Now;
                string logText = "[" + faileTIme + "]" + Environment.NewLine;
                logText += "例外の生じた処理：レポート名の取得" + Environment.NewLine;
                logText += ex.Message + "\n" + ex.StackTrace + Environment.NewLine;
                File.AppendAllText(System.IO.Path.Combine(workLogPath, "CSRender.log"), logText);
                //referenceErrorFlag = true;
            }

            //指定先にレポートを移動
            CompareTIFF.moveReport(workBox.Text, workDir);

            //レポートのパスを表示
            ResultConsole.Text += "　検版レポートのパス：";
            ResultConsole.Text += System.IO.Path.Combine(workBox.Text, "report", PDFName);
            ResultConsole.Text += "\r\n";
            if(reportBox.Text == "")
            {
                reportBox.Text = System.IO.Path.Combine(workBox.Text, "report", PDFName);
            }
            
            //パラメータを次回初期値用に保存
            Properties.Settings.Default.resolutionSetting = ResolutionBox.Value;
            Properties.Settings.Default.formatSetting = FileSelect.Text;
            Properties.Settings.Default.shiftPixelSetting = PositionBox.Value;
            Properties.Settings.Default.colorMarginSetting = GradationBox.Value;
            Properties.Settings.Default.removePointSetting = SmallDiffBox.Value;
            Properties.Settings.Default.shadingOffSetting = VisualBox.Value;
            Properties.Settings.Default.workSpaceSetting = workBox.Text;
            Properties.Settings.Default.targetSetting = targetBox.Text;
            Properties.Settings.Default.referenceSetting = referenceBox.Text;
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// UIに検版結果を出力する。
        /// </summary>
        /// <param name="reportFiles">作業フォルダ内のlogファイルを全て格納する配列</param>
        /// <param name="logfileName">作成されたlogファイルの名称</param>
        /// <param name="logString">logファイルを読み取るリーダー</param>
        /// <param name="tranceString">リーダーで読み取った行の文字列</param>
        /// <param name="lineCount">リーダーがその時点で読み込んでいる行数</param>
        private void outputLog(string workDir)
        {
            //logファイルを読み取り（1行ずつ）
            string[] reportFiles = System.IO.Directory.GetFiles(workDir, "*.log", System.IO.SearchOption.TopDirectoryOnly);
            string logfileName = reportFiles[0];
            StreamReader logString = new StreamReader(logfileName, Encoding.GetEncoding("Shift-JIS"));//Shift-JISでエンコーディング
            string tranceString = "";
            int lineCount = 0;
            //ファイルから読み取った結果をUIに出力
            while (logString.EndOfStream == false)
            {
                tranceString = logString.ReadLine();
                lineCount++;
                //logファイルにある処理日時表示を除去
                if (lineCount == 14 || lineCount == 19 || lineCount == 36 || lineCount == 37 || lineCount == 38 || lineCount == 39)
                {
                    tranceString = tranceString.Substring(0,66);
                }
                if (lineCount > 13 && lineCount < 40)//必要なところだけをUIに記述
                {
                    ResultConsole.Text += tranceString + "\r\n";
                    ResultConsole.ScrollToEnd();
                    DoEvents();
                }
            }
            logString.Close();
            
        }

        /// <summary>
        /// TIFF画像化を実行する
        /// </summary>
        /// <param name="pageFlag">ページ範囲の指定があるかどうかを示すフラグ</param>
        /// <param name="selectedPage">入力されたページ数</param>
        /// <param name="TIFFresult">CSRenderの処理出力文</param>
        /// 
        private void TIFFButtonClick(object sender, RoutedEventArgs e)
        {
            //出力メニューにメッセージを出力
            ResultConsole.Text += "<変換開始>\r\n";
            ResultConsole.Text += "　PDFを" + FileSelect.Text + "に変換します\r\n";
            ResultConsole.Text += "\r\n";
            DoEvents();

            //必要に応じてページ引数を指定
            bool pageFlag = false;
            string selectedPage = "";
            if (PageRange.Text == "指定")
            {
                pageFlag = true;
                selectedPage = pageBox.Text;
            }

            //対象フォルダのpathが存在するかチェック
            if (!Directory.Exists(targetBox.Text) && !File.Exists(targetBox.Text))
            {
                CustomMsgBox.Show(mainWindow, "指定されたファイルあるいはフォルダが存在しません。" +
                    "\nもう一度TIFF出力する対象を設定してください。", "The specified file or folder does not exist", MessageBoxButton.OK, MessageBoxImage.Information);
                ResultConsole.Text += "　指定された対象ファイルあるいはフォルダを発見できませんでした\r\n";
                ResultConsole.Text += "<変換中止>\r\n";
                Properties.Settings.Default.targetSetting = "";
                Properties.Settings.Default.Save();
                return;
            }

            //出力フォルダのpathチェック
            if (workBox.Text != "")
            {
                if (!Directory.Exists(workBox.Text) && !File.Exists(workBox.Text))//pathのチェック
                {
                    CustomMsgBox.Show(mainWindow, "指定された作業フォルダが存在しません。" +
                        "\nもう一度設定してください。", "The specified reference file or folder does not exist", MessageBoxButton.OK, MessageBoxImage.Information);
                    ResultConsole.Text += "　指定された作業フォルダを発見できませんでした\r\n";
                    ResultConsole.Text += "<変換中止>\r\n";
                    workBox.Text = "";
                    Properties.Settings.Default.workSpaceSetting = "";
                    Properties.Settings.Default.Save();
                    return;
                }
            }
            
            //CSRenderの実行
            string TIFFresult = 
                OutputTIFF.runCSRender(ResolutionBox.Text, FileSelect.Text, pageFlag, selectedPage, targetBox.Text, workBox.Text);
            
            ResultConsole.Text += TIFFresult;
            ResultConsole.Text += "\r\n<変換終了>\r\n";
            ResultConsole.ScrollToEnd();

            //パラメータを次回初期値用に保存
            Properties.Settings.Default.resolutionSetting = ResolutionBox.Value;
            Properties.Settings.Default.formatSetting = FileSelect.Text;
            Properties.Settings.Default.workSpaceSetting = workBox.Text;
            Properties.Settings.Default.targetSetting = targetBox.Text;
            Properties.Settings.Default.Save();
        }

        //メニュを明示的に更新する
        private void DoEvents()
        {
            DispatcherFrame frame = new DispatcherFrame();
            var callback = new DispatcherOperationCallback(ExitFrames);
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, callback, frame);
            Dispatcher.PushFrame(frame);
        }

        //実行中のオブジェクトを読み込み
        private object ExitFrames(object obj)
        {
            ((DispatcherFrame)obj).Continue = false;
            return null;
        }
    }
}
