// WideMargin. Simple fast bible software.
// Copyright (C) 2011  Daniel Hughes
//
// 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;
using System.Collections.Generic;
using System.Linq;
using WideMargin.MVCInterfaces;
using Gtk;
using WideMargin.Utilities;
using System.Threading;

namespace WideMargin.GUI
{
	/// <summary>
	/// Page which shows a bible passage
	/// </summary>
	[System.ComponentModel.ToolboxItem(true)]
	public partial class PassagePage : Gtk.Bin, IPassageView
	{	
		private EventLocker _eventLocker = new EventLocker();
		private EventHandler<EventArgs> _requestNext;
		private EventHandler<EventArgs> _requestPrevious;
		private TextView _passageTextView;
		private GaplessScrolledWindow _scrolledWindow;
		private const int _textColumWidth = 450;
		private int _textViewWidth = 0;
		private System.Action _adjustmentChangedAction;

		/// <summary>
		/// Constructs a PassagePage
		/// </summary>
		public PassagePage ()
		{
			this.Build ();
			
			_passageTextView = new TextView();
			_passageTextView.WrapMode = WrapMode.Word;
			
			_vbox.Remove(_buttonBox);
			
			_vbox.PackStart(CreatTextArea());
			_vbox.PackEnd(_buttonBox, false, false, 0);
			_previousButton.Image = new Image(ImageCache.Get().LongBackArrow);
			_nextButton.Image = new Image(ImageCache.Get().LongForwardArrow);
		}
		
		/// <summary>
		/// Creates the text area
		/// </summary>
		/// <returns>
		/// text area widget
		/// </returns>
		private Widget CreatTextArea()
		{			
			_passageTextView.Editable = false;			
			this.SizeAllocated += HandlePassageTextViewSizeAllocated;
			
			_scrolledWindow = new GaplessScrolledWindow();
			_scrolledWindow.Add(_passageTextView);
			_scrolledWindow.VscrollbarPolicy = PolicyType.Automatic;
			_scrolledWindow.Vadjustment.Changed += HandledVadjustmentChanged;
				
			return _scrolledWindow;
		}
		
		/// <summary>
		/// Vadjustment has changed,
		/// run the adjustment changed action.
		/// </summary>
		private void HandledVadjustmentChanged(object sender, EventArgs args)
		{
			System.Action action = _adjustmentChangedAction;
			if(action != null)
			{
				Application.Invoke((_,__) =>
				{
					action();
				});
			}
		}
		
		/// <summary>
		/// The PassageTextView has been resized so we need to adjust the margin
		/// to maintain the text width
		/// </summary>
		private void HandlePassageTextViewSizeAllocated (object o, SizeAllocatedArgs args)
		{
			int newTextWidth = args.Allocation.Width;
			if(newTextWidth == _textViewWidth)
			{
				return;	
			}
			_textViewWidth = newTextWidth;
			if(_textColumWidth >= _textViewWidth)
			{
				_passageTextView.LeftMargin = 0;
				_passageTextView.RightMargin = 0;
			}
			int margin = (_textViewWidth - _textColumWidth)/2;


			_passageTextView.LeftMargin = margin;
			_passageTextView.RightMargin = margin;
		}
		
		/// <summary>
		/// User has clicked on the next button.
		/// Let the controller know.
		/// </summary>
		private void NextButton_Clicked (object sender, System.EventArgs e)
		{
			_requestNext.Fire(sender, new EventArgs());
		}
		
		/// <summary>
		/// User has clicked on the previous button.
		/// Let the controller know.
		/// </summary>
		private void PreviousButton_Clicked (object sender, System.EventArgs e)
		{
			_requestPrevious.Fire(sender, new EventArgs());
		}
		
		/// <summary>
		/// Occurs when the user clicks on the next button.
		/// </summary>
		public event EventHandler<EventArgs> RequestNext
		{
			add
			{	
				_eventLocker.Add(ref _requestNext, value);
			}
			remove
			{
				_eventLocker.Remove(ref _requestNext, value);
			}
		}
		
		/// <summary>
		/// Occurs when the user clicks on the previous button.
		/// </summary>
		public event EventHandler<EventArgs> RequestPrevious
		{
			add
			{	
				_eventLocker.Add(ref _requestPrevious, value);
			}
			remove
			{
				_eventLocker.Remove(ref _requestPrevious, value);
			}
		}
		
		/// <summary>
		/// Show the verses for this passage to the user.
		/// </summary>
		/// <param name="searchResults">
		/// passages to show.
		/// </param>
		public void ShowVerses(IEnumerable<IVerse> searchResults)
		{
			var passageBuilder = new StringBuilder();
			foreach(IVerse verse in searchResults)
			{
				passageBuilder.AppendFormat("{0}.  {1}{2}", verse.VerseNumber, verse.Contents, Environment.NewLine);
			}
			
			this.Invoke(() =>
			{
				_adjustmentChangedAction = null;
				_passageTextView.Buffer.Text = passageBuilder.ToString();
			});
		}
		
		/// <summary>
		/// Scrolls to the specified verse
		/// </summary>
		/// <param name="verse">Verse to scroll to</param>
		public void ScrollToVerse(IVerse verse)
		{
			this.Invoke(() =>
			{
				_adjustmentChangedAction = () =>
				{
					int index = _passageTextView.Buffer.Text.IndexOf(verse.Contents);
					TextIter verseIter = _passageTextView.Buffer.GetIterAtOffset(index);
					TextMark mark = _passageTextView.Buffer.CreateMark("VerseTarget", verseIter, true);
					_passageTextView.ScrollToMark(mark, 0.0, true, 0, 0);
					var verseEnd = _passageTextView.Buffer.GetIterAtOffset(index + verse.Contents.Length);
					_passageTextView.Buffer.SelectRange(verseIter, verseEnd);
				};
				_adjustmentChangedAction();
				
			});
		}
		
		public event EventHandler<LinkClickedEventArgs<IVerse>> VerseLinkActivated;
	}
}

