/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2013 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 KeePass.Util.Spr;

using KeePassLib;
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Delegates;
using KeePassLib.Security;
using KeePassLib.Utility;

namespace KeePass.Util
{
	/// <summary>
	/// This class contains various static functions for entry operations.
	/// </summary>
	public static class EntryUtil
	{

		// Old format name (<= 2.14): "KeePassEntriesCF"
		public const string ClipFormatEntries = "KeePassEntriesCX";

		public static string FillPlaceholders(string strText, SprContext ctx)
		{
			if((ctx == null) || (ctx.Entry == null)) return strText;

			string str = strText;

		/*NOT SUPPORTED CURRENTLY	if((ctx.Flags & SprCompileFlags.NewPassword) != SprCompileFlags.None)
				str = ReplaceNewPasswordPlaceholder(str, ctx);
*/
			if((ctx.Flags & SprCompileFlags.HmacOtp) != SprCompileFlags.None)
				str = ReplaceHmacOtpPlaceholder(str, ctx);

			return str;
		}

/*		private static string ReplaceNewPasswordPlaceholder(string strText,
			SprContext ctx)
		{
			PwEntry pe = ctx.Entry;
			PwDatabase pd = ctx.Database;
			if((pe == null) || (pd == null)) return strText;

			string str = strText;

			const string strNewPwPlh = @"{NEWPASSWORD}";
			if(str.IndexOf(strNewPwPlh, StrUtil.CaseIgnoreCmp) >= 0)
			{
				ProtectedString psAutoGen;
				PwgError e = PwGenerator.Generate(out psAutoGen,
					Program.Config.PasswordGenerator.AutoGeneratedPasswordsProfile,
					null, Program.PwGeneratorPool);
				psAutoGen = psAutoGen.WithProtection(pd.MemoryProtection.ProtectPassword);

				if(e == PwgError.Success)
				{
					pe.CreateBackup(pd);
					pe.Strings.Set(PwDefs.PasswordField, psAutoGen);
					pe.Touch(true, false);
					pd.Modified = true;

					string strIns = SprEngine.TransformContent(psAutoGen.ReadString(), ctx);
					str = StrUtil.ReplaceCaseInsensitive(str, strNewPwPlh, strIns);
				}
			}

			return str;
		}
*/
		private static string ReplaceHmacOtpPlaceholder(string strText,
			SprContext ctx)
		{
			PwEntry pe = ctx.Entry;
			PwDatabase pd = ctx.Database;
			if((pe == null) || (pd == null)) return strText;

			string str = strText;

			const string strHmacOtpPlh = @"{HMACOTP}";
			if(str.IndexOf(strHmacOtpPlh, StrUtil.CaseIgnoreCmp) >= 0)
			{
				const string strKeyField = "HmacOtp-Secret";
				const string strCounterField = "HmacOtp-Counter";

				byte[] pbSecret = StrUtil.Utf8.GetBytes(pe.Strings.ReadSafe(
					strKeyField));

				string strCounter = pe.Strings.ReadSafe(strCounterField);
				ulong uCounter;
				ulong.TryParse(strCounter, out uCounter);

				string strValue = HmacOtp.Generate(pbSecret, uCounter, 6, false, -1);

				pe.Strings.Set(strCounterField, new ProtectedString(false,
					(uCounter + 1).ToString()));
				pd.Modified = true;

				str = StrUtil.ReplaceCaseInsensitive(str, strHmacOtpPlh, strValue);
			}

			return str;
		}

		public static bool EntriesHaveSameParent(PwObjectList<PwEntry> v)
		{
			if(v == null) { Debug.Assert(false); return true; }
			if(v.UCount == 0) return true;

			PwGroup pg = v.GetAt(0).ParentGroup;
			foreach(PwEntry pe in v)
			{
				if(pe.ParentGroup != pg) return false;
			}

			return true;
		}

		public static void ReorderEntriesAsInDatabase(PwObjectList<PwEntry> v,
			PwDatabase pd)
		{
			if((v == null) || (pd == null)) { Debug.Assert(false); return; }
			if(pd.RootGroup == null) { Debug.Assert(false); return; } // DB must be open

			PwObjectList<PwEntry> vRem = v.CloneShallow();
			v.Clear();

			EntryHandler eh = delegate(PwEntry pe)
			{
				int p = vRem.IndexOf(pe);
				if(p >= 0)
				{
					v.Add(pe);
					vRem.RemoveAt((uint)p);
				}

				return true;
			};

			pd.RootGroup.TraverseTree(TraversalMethod.PreOrder, null, eh);

			foreach(PwEntry peRem in vRem) v.Add(peRem); // Entries not found
		}


		public static string CreateSummaryList(PwGroup pgItems, bool bStartWithNewPar)
		{
			List<PwEntry> l = pgItems.GetEntries(true).CloneShallowToList();
			string str = CreateSummaryList(pgItems, l.ToArray());

			if((str.Length == 0) || !bStartWithNewPar) return str;
			return (MessageService.NewParagraph + str);
		}

		public static string CreateSummaryList(PwGroup pgSubGroups, PwEntry[] vEntries)
		{
			int nMaxEntries = 10;
			string strSummary = string.Empty;

			if(pgSubGroups != null)
			{
				PwObjectList<PwGroup> vGroups = pgSubGroups.GetGroups(true);
				if(vGroups.UCount > 0)
				{
					StringBuilder sbGroups = new StringBuilder();
					sbGroups.Append("- ");
					uint uToList = Math.Min(3U, vGroups.UCount);
					for(uint u = 0; u < uToList; ++u)
					{
						if(sbGroups.Length > 2) sbGroups.Append(", ");
						sbGroups.Append(vGroups.GetAt(u).Name);
					}
					if(uToList < vGroups.UCount) sbGroups.Append(", ...");
					strSummary += sbGroups.ToString(); // New line below

					nMaxEntries -= 2;
				}
			}

			int nSummaryShow = Math.Min(nMaxEntries, vEntries.Length);
			if(nSummaryShow == (vEntries.Length - 1)) --nSummaryShow; // Plural msg

			for(int iSumEnum = 0; iSumEnum < nSummaryShow; ++iSumEnum)
			{
				if(strSummary.Length > 0) strSummary += MessageService.NewLine;

				PwEntry pe = vEntries[iSumEnum];
				strSummary += ("- " + StrUtil.CompactString3Dots(
					pe.Strings.ReadSafe(PwDefs.TitleField), 39));
				if(PwDefs.IsTanEntry(pe))
				{
					string strTanIdx = pe.Strings.ReadSafe(PwDefs.UserNameField);
					if(!string.IsNullOrEmpty(strTanIdx))
						strSummary += (@" (#" + strTanIdx + @")");
				}
			}

			return strSummary;
		}
	}
}
