// 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.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Linq;
using System.Linq;
using WideMargin.MVCInterfaces;

namespace WideMargin.Database
{
	public class BibleBarDecoder
	{
		public BibleBarDecoder ()
		{
		}
		
		public BibleBarResult Decode(string queryText)
		{
			PassageResult passageResult;
			if(PassageResult.TryParse(queryText, out passageResult))
			{
				return passageResult;
			}
			return new SearchResult(queryText);
		}
	}
	
	public abstract class BibleBarResult
	{
		public BibleBarResult(string queryText)
		{
			QueryText = queryText;
		}
		
		public string QueryText
		{
			get;
			private set;
		}
		
		public abstract IEnumerable<IVerse> GetVerses(BibleDatabase database);
	}
	
	public class PassageResult : BibleBarResult
	{
		
		private PassageResult(string queryText, string book) 
			: this(queryText, book, 1, 1)
		{
		}
		
		private PassageResult(string queryText, string book, int chapter) 
			: this(queryText, book, chapter, 1)
		{
		}
		
		private PassageResult(string queryText, string book, int chapter, int verse) 
			: base(queryText)
		{
			Book = book;
			Chapter = chapter;
			Verse = verse;
		}
		
		public string Book
		{
			get;
			private set;
		}
		
		public int Chapter
		{
			get;
			private set;
		}
		
		public int Verse
		{
			get;
			private set;
		}
		
		public static bool TryParse(string queryText, out PassageResult passageResult)
		{
			string[] parts = queryText.Split(' ');
			int currentPart = 0;
			
			//is their at least one part
			if(parts.Length == 0)
			{
				passageResult = null;
				return false;	
			}
			
			//does it start with a book
			string book = parts[0];
			currentPart++;
			int bookNumber;
			if(int.TryParse(book, out bookNumber))
			{
				//starts with a number so first two parts could make up a book
				if(parts.Length == 1)
				{
					passageResult = null;
					return false; //only one part and its a number	
				}
				book += " " + parts[1];
				currentPart++;
			}
			
			while(currentPart < parts.Length && !IsInteger(parts[currentPart]) && !parts[currentPart].Contains(":"))
			{
				book = book + " " + parts[currentPart];
				currentPart++;
			}
			
			if(!BookList.Get().IsBook(book))
			{
				passageResult = null;
				return false;
			}
			
			if(parts.Length == currentPart)
			{
				//its a book only request
				passageResult = new PassageResult(queryText, book);
				return true;
			}
			
			//check for chapter only and no verse
			int chapter;
			if(!parts[currentPart].Contains(":"))
			{
				
				if(!int.TryParse(parts[currentPart], out chapter))
				{
					passageResult = null;
					return false;
				}
				passageResult = new PassageResult(queryText, book, chapter);
				return true;
			}
			
			
			//is the next part Chapter:Verse
			string[] chapterAndVerse = parts[currentPart].Split(':');
			if(!int.TryParse(chapterAndVerse[0], out chapter))
			{
				//chapter was not a number
				passageResult = null;
				return false;
			}
			int verse;
			if(!int.TryParse(chapterAndVerse[1], out verse))
			{
				//chapter was not a number
				passageResult = null;
				return false;
			}
			passageResult = new PassageResult(queryText, book, chapter, verse);
			return true;
			
		}
		
		public override IEnumerable<IVerse> GetVerses (BibleDatabase database)
		{
			return database.GetChapter(Book, Chapter);
		}
		
		/// <summary>
		/// Checks if the specified text is a integer
		/// </summary>
		/// <param name="text">text to check</param>
		/// <returns>true if integer otherwise false</returns>
		private static bool IsInteger(string text)
		{
			int notUsed = 0;
			if(int.TryParse(text, out notUsed))
			{
				return true;	
			}		   
			return false;
		}
	}
	
}

