/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>

  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 2 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, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

using KeePassLib;
using KeePassLib.Interfaces;

using SprRefsCache = System.Collections.Generic.Dictionary<string, string>;

namespace KeePass.Util.Spr
{
	[Flags]
	public enum SprCompileFlags
	{
		None = 0,

		AppPaths = 0x1, // Paths to IE, Firefox, Opera, ...
		PickChars = 0x2,
		EntryStrings = 0x4,
		EntryStringsSpecial = 0x8, // {URL:RMVSCM}, ...
		PasswordEnc = 0x10,
		Group = 0x20,
		Paths = 0x40, // App-dir, doc-dir, path sep, ...
		AutoType = 0x80, // Replacements like {CLEARFIELD}, ...
		DateTime = 0x100,
		References = 0x200,
		EnvVars = 0x400,
		NewPassword = 0x800,
		HmacOtp = 0x1000,
		Comments = 0x2000,
		TextTransforms = 0x10000,

		ExtActive = 0x4000, // Active transformations provided by plugins
		ExtNonActive = 0x8000, // Non-active transformations provided by plugins

		// Next free: 0x20000
		All = 0x1FFFF,

		// Internal:
		UIInteractive = SprCompileFlags.PickChars,
		StateChanging = (SprCompileFlags.NewPassword | SprCompileFlags.HmacOtp),

		Active = (SprCompileFlags.UIInteractive | SprCompileFlags.StateChanging |
			SprCompileFlags.ExtActive),
		NonActive = (SprCompileFlags.All & ~SprCompileFlags.Active),

		Deref = (SprCompileFlags.EntryStrings | SprCompileFlags.EntryStringsSpecial |
			SprCompileFlags.References)
	}

	public sealed class SprContext
	{
		private PwEntry m_pe = null;
		public PwEntry Entry
		{
			get { return m_pe; }
			set { m_pe = value; }
		}

		private PwDatabase m_pd = null;
		public PwDatabase Database
		{
			get { return m_pd; }
			set { m_pd = value; }
		}

		private bool m_bMakeAT = false;
		public bool EncodeAsAutoTypeSequence
		{
			get { return m_bMakeAT; }
			set { m_bMakeAT = value; }
		}

		private bool m_bMakeCmdQuotes = false;
		public bool EncodeQuotesForCommandLine
		{
			get { return m_bMakeCmdQuotes; }
			set { m_bMakeCmdQuotes = value; }
		}

		private bool m_bForcePlainTextPasswords = true;
		public bool ForcePlainTextPasswords
		{
			get { return m_bForcePlainTextPasswords; }
			set { m_bForcePlainTextPasswords = value; }
		}

		private SprCompileFlags m_flags = SprCompileFlags.All;
		public SprCompileFlags Flags
		{
			get { return m_flags; }
			set { m_flags = value; }
		}

		private SprRefsCache m_refsCache = new SprRefsCache();
		/// <summary>
		/// Used internally by <c>SprEngine</c>; don't modify it.
		/// </summary>
		internal SprRefsCache RefsCache
		{
			get { return m_refsCache; }
		}

		// private bool m_bNoUrlSchemeOnce = false;
		// /// <summary>
		// /// Used internally by <c>SprEngine</c>; don't modify it.
		// /// </summary>
		// internal bool UrlRemoveSchemeOnce
		// {
		//	get { return m_bNoUrlSchemeOnce; }
		//	set { m_bNoUrlSchemeOnce = value; }
		// }

		public SprContext() { }

		public SprContext(PwEntry pe, PwDatabase pd, SprCompileFlags fl)
		{
			Init(pe, pd, false, false, fl);
		}

		public SprContext(PwEntry pe, PwDatabase pd, SprCompileFlags fl,
			bool bEncodeAsAutoTypeSequence, bool bEncodeQuotesForCommandLine)
		{
			Init(pe, pd, bEncodeAsAutoTypeSequence, bEncodeQuotesForCommandLine, fl);
		}

		private void Init(PwEntry pe, PwDatabase pd, bool bAT, bool bCmdQuotes,
			SprCompileFlags fl)
		{
			m_pe = pe;
			m_pd = pd;
			m_bMakeAT = bAT;
			m_bMakeCmdQuotes = bCmdQuotes;
			m_flags = fl;
		}

		public SprContext Clone()
		{
			return (SprContext)this.MemberwiseClone();
		}

		/// <summary>
		/// Used by <c>SprEngine</c> internally; do not use.
		/// </summary>
		internal SprContext WithoutContentTransformations()
		{
			SprContext ctx = Clone();

			ctx.m_bMakeAT = false;
			ctx.m_bMakeCmdQuotes = false;
			// ctx.m_bNoUrlSchemeOnce = false;

			Debug.Assert(object.ReferenceEquals(m_pe, ctx.m_pe));
			Debug.Assert(object.ReferenceEquals(m_pd, ctx.m_pd));
			Debug.Assert(object.ReferenceEquals(m_refsCache, ctx.m_refsCache));
			return ctx;
		}
	}

	public sealed class SprEventArgs : EventArgs
	{
		private string m_str = string.Empty;
		public string Text
		{
			get { return m_str; }
			set
			{
				if(value == null) throw new ArgumentNullException("value");
				m_str = value;
			}
		}

		private SprContext m_ctx = null;
		public SprContext Context
		{
			get { return m_ctx; }
		}

		public SprEventArgs() { }

		public SprEventArgs(string strText, SprContext ctx)
		{
			if(strText == null) throw new ArgumentNullException("strText");
			// ctx == null is allowed

			m_str = strText;
			m_ctx = ctx;
		}
	}
}
