// 
// Hiero
// Copyright (c) 2015  Barry Block 
// 
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version. 
// 
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE.  See the GNU General Public License for more details. 
// 
// You should have received a copy of the GNU General Public License along with
// this program.  If not, see <http://www.gnu.org/licenses/>. 
//

using System;
using System.Text.RegularExpressions;
using Gtk;

namespace Hiero
{
   public class EditDialog : Gtk.Dialog
   {
      private TextView textview;
      private Label countLabel;
      private string SearchText;
      private TextTag highlightTag; 
         // The text tag used to highlight search results.

      // Returns the edited text.
      public string Text
      {
         get { return textview.Buffer.Text.Replace("\t", " "); }
      }

      // Returns whether the node's text has been modified.
      public bool TextModified
      {
         get { return textview.Buffer.Modified; }
      }

      // Returns the text statistics in the form of a string.
      private string TextStats
      {
         get { return "[" + Text.Length.ToString() + ", " + Document.WordCount(Text) + "]"; }
      }

      // Selects all of the text.
      private void SelectAllText(TextView textview)
      {
         TextIter start = textview.Buffer.StartIter;
         TextIter end = textview.Buffer.EndIter;
         textview.Buffer.SelectRange(start, end);
      }

      public EditDialog(Gtk.Window parent, Document theDoc, int width, int height, 
      string font, string text, string searchText, string highlightColor) : base("Edit Text", 
      parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, Gtk.Stock.Cancel, 
      ResponseType.Cancel, Gtk.Stock.Ok, ResponseType.Ok)
      {
         SearchText = searchText; 

         SetDefaultSize(width, height); 

         TreeStore model = (TreeStore) theDoc.Tree.Model;

         // Build the content area of the dialog window:

         textview = new TextView();
         textview.Visible = true;
         textview.CanFocus = true;
         textview.WrapMode = WrapMode.WordChar;
         textview.AcceptsTab = false;
         textview.ModifyFont(Pango.FontDescription.FromString(font));
         textview.Buffer.Text = text;
         textview.Buffer.Modified = false;
         textview.Buffer.Changed += OnTextChanged;
         if ((text == MainClass.newNodePlaceholder) || (text == MainClass.initRootText)) SelectAllText(textview);

         ScrolledWindow scrolled = new ScrolledWindow();
         scrolled.Visible = true;
         scrolled.CanFocus = true;
         scrolled.ShadowType = ShadowType.In;
         scrolled.HscrollbarPolicy = PolicyType.Automatic;
         scrolled.VscrollbarPolicy = PolicyType.Automatic;
         scrolled.Add(textview);
         this.VBox.PackStart(scrolled, true, true, 1);

         HBox statusBox = new HBox(false, 6);
         countLabel = new Label(TextStats);
         statusBox.PackStart(countLabel, false, false, 1);
         this.VBox.PackStart(statusBox, false, false, 1);

         // Create text tag used for highlighting search results:

         highlightTag = new TextTag("highlight"); 
         Gdk.Color tempColor = new Gdk.Color();
         Gdk.Color.Parse(highlightColor, ref tempColor);
         highlightTag.BackgroundGdk = tempColor;
         textview.Buffer.TagTable.Add(highlightTag);

         OnTextChanged(new object(), new EventArgs());
         this.ShowAll();
      }

      // Returns 0-based index of theStr found in source. Also outputs the
      // actual string that is matched (for use if matching regex pattern).
      protected static int StringPos(string theStr, string source, bool ignoringCase, bool isRegEx, 
      out string matchStr)
      {
         int result;
         
         if (isRegEx)
         {
            RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
            if (ignoringCase) options = options | RegexOptions.IgnoreCase;
            Match match = Regex.Match(source, theStr, options);
            
            if (match.Success)
            {
               result = match.Index;
               matchStr = match.Value;
            }
            else
            {
               // The following is needed because Regex.Match doesn't 
               // set match.Index to -1 when match fails.
               
               result = -1;
               matchStr = string.Empty;
            }
         }
         else
         {
            if (ignoringCase)
               result = source.IndexOf(theStr, StringComparison.InvariantCultureIgnoreCase);
            else
               result = source.IndexOf(theStr);

            matchStr = theStr;
         }
         
         return result;
      }

      // Highlights all of the search results in the editor's text view widget.
      private void HighlightSearchResults()
      {
         string theText = textview.Buffer.Text;
         int searchLen = SearchText.Length;

         if ((searchLen > 0) && (theText.Length >= searchLen))
         {
            textview.Buffer.RemoveAllTags(textview.Buffer.StartIter, textview.Buffer.EndIter);
   
            int i;
            string matchStr;
            int offset = 0;
   
            TextIter startIter = new TextIter(); 
            TextIter endIter = new TextIter(); 
   
            while ((i = StringPos(SearchText, theText, true, false, out matchStr)) != -1)
            {
               int index = offset + i;
   
               startIter = textview.Buffer.StartIter;
               startIter.ForwardChars(index);
               endIter = startIter;
               endIter.ForwardChars(searchLen);
               textview.Buffer.ApplyTag(highlightTag, startIter, endIter);
   
               theText = theText.Substring(i + searchLen);
               offset += i + searchLen;
            }
         }
      }

      private void OnTextChanged(object o, EventArgs args)
      {
         // Update statistics:

         countLabel.Text = TextStats;

         // Highlight all search results:

         HighlightSearchResults();
      }

      protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
      {
         Gdk.Key theKey = evnt.Key;
         char theChar = (char) evnt.KeyValue;
         //Console.WriteLine("KeyValue: " + evnt.KeyValue);

         bool controlPressed = (evnt.State & Gdk.ModifierType.ControlMask) != 0;   
         bool altPressed = (evnt.State & Gdk.ModifierType.Mod1Mask) != 0;            
         bool shiftPressed = (evnt.State & Gdk.ModifierType.ShiftMask) != 0;

         if (!altPressed && controlPressed && !shiftPressed && (theKey == Gdk.Key.Return))
         {
            // A CTRL-ENTER was pressed. Treat as though the "Ok" button was clicked:

            this.Respond(ResponseType.Ok);
            return true;
         }

         return base.OnKeyPressEvent (evnt);
      }
   }
}

