// Bookmarks.cs
//
//  Copyright (C) 2009 Christian Eide
//
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//

using System;
using System.Xml;
using System.Collections;
using System.Collections.Generic;

namespace bareFTP.Preferences.Bookmarks
{
	
	public class Bookmarks
	{
		BookmarkFolder rootItem;
		PwdBackend pwdBackend;
		Config conf;
		XmlDocument bookmarks;
		private bool use_keyring;
		
		public Bookmarks()
		{
			this.conf = new Config(string.Empty);
			use_keyring = conf.General_UseGnomeKeyring;
			
			pwdBackend = new PwdBackend();
			
			try
			{
				pwdBackend.CheckKeyring();	
			}
			catch
			{
				pwdBackend = null;
				use_keyring = false;
			}
			
			string path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "bareftp/bookmarks.xml");
			if(System.IO.File.Exists(path))
			{
				bookmarks = new XmlDocument();
		 		bookmarks.Load(path);
				XmlNode blist = bookmarks.SelectSingleNode("/bookmarks");
			
				rootItem = new BookmarkFolder(string.Empty);
				Traverser((XmlElement)blist, rootItem);
			}
		}
		
		public Bookmarks(string filename)
		{
			pwdBackend = null;
			this.conf = new Config(string.Empty);
			use_keyring = conf.General_UseGnomeKeyring;
			
			if(System.IO.File.Exists(filename))
			{
				bookmarks = new XmlDocument();
		 		bookmarks.Load(filename);
				XmlNode blist = bookmarks.SelectSingleNode("/bookmarks");
			
				rootItem = new BookmarkFolder(string.Empty);
				Traverser((XmlElement)blist, rootItem);
			}
			
		}
		
		public bool BackendOperational
		{
			get
			{
				PwdBackend backend = new PwdBackend();
				try
				{
					if(conf.General_UseGnomeKeyring)
						backend.CheckKeyring();
					return true;
				}
				catch
				{
					return false;	
				}
			}
		}
		
		private void Traverser(XmlElement element, BookmarkFolder folder)
		{
			IEnumerator iter = element.ChildNodes.GetEnumerator();
			while(iter.MoveNext())
			{
				try
				{
					XmlNode node = iter.Current as XmlNode;
					if(node.Name == "folder")
					{
						XmlElement el = node as XmlElement;
						BookmarkFolder nf = new BookmarkFolder(el.GetAttribute("name"));
						folder.Items.Add(nf);
						if(el.HasChildNodes)
							Traverser(el, nf);
						
					}
					else if(node.Name == "bookmark")
					{
						XmlElement el = node as XmlElement;
						BookmarkEntry entry = new BookmarkEntry(el.GetAttribute("name"));
						
						entry.Host = el.SelectSingleNode("host").InnerText;
						entry.Port = el.SelectSingleNode("port").InnerText;
						entry.User = el.SelectSingleNode("user").InnerText;
						XmlNode pwdnode = el.SelectSingleNode("password");
						
						if(pwdBackend != null && pwdnode.Attributes.Count > 0 && pwdnode.Attributes.GetNamedItem("store") != null)
						{
							if(pwdnode.Attributes.GetNamedItem("store").Value == "keyring")
							{
								int keyid = -1;
								try
								{
									if(pwdnode.Attributes.Count > 1)
									{
										keyid = Convert.ToInt32(pwdnode.Attributes.GetNamedItem("keyid").Value);
										entry.KeyId = keyid;
									}
								} catch {}
								
								//entry.Pass = pwdBackend.GetPwd(entry.User, entry.Host, entry.Protocol, entry.Port, keyid);
								entry.Pass = pwdBackend.GetPwd(keyid);
							}
						}
						
						//if(pwdBackend == null)
						//	entry.IsNew = true;
						
						if(string.IsNullOrEmpty(entry.Pass))
							entry.Pass = el.SelectSingleNode("password").InnerText;
						
						entry.Protocol = Convert.ToInt32(el.SelectSingleNode("protocol").InnerText);
						entry.RemotePath = el.SelectSingleNode("remotepath").InnerText;
						entry.LocalPath = el.SelectSingleNode("localpath").InnerText;
						entry.CharSet = el.SelectSingleNode("charset").InnerText;
						entry.ShowHidden = bool.Parse(el.SelectSingleNode("showhidden").InnerText);
						entry.Passive = bool.Parse(el.SelectSingleNode("passive").InnerText);
						entry.EncryptData = el.SelectSingleNode("encryptdata").InnerText;
						if(el.SelectSingleNode("syncronized_browse") != null)
							entry.SyncedBrowse = bool.Parse(el.SelectSingleNode("syncronized_browse").InnerText);
						else
							entry.SyncedBrowse = false;
						folder.Items.Add(entry);
					}
				}
				catch(Exception ex)
				{
					Console.WriteLine("Bookmark parse error: " + ex.ToString());
				}
				
			}
		}

		public void Save(bool use_keyring)
		{
			this.use_keyring = use_keyring;
			Save(bookmarks);
		}
		
		public void Save(XmlDocument doc)
		{
			if(doc == null)
				return;
			
			SavePasswords(doc);
			
			string path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "bareftp/bookmarks.xml");
			if(!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(path)))
			{
				System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
			}
			System.IO.StreamWriter sw = new System.IO.StreamWriter(path, false, new System.Text.UTF8Encoding(false));
			doc.Save(sw);
			sw.Close();
			
			// Set strict permissions on file and directory since we maybe store passwords in clear text
			Mono.Unix.UnixFileSystemInfo ufsd = Mono.Unix.UnixFileSystemInfo.GetFileSystemEntry(System.IO.Path.GetDirectoryName(path));
			ufsd.FileAccessPermissions = (Mono.Unix.FileAccessPermissions)((7 << 6) | 0 | 0);
			
			Mono.Unix.UnixFileSystemInfo ufsf = Mono.Unix.UnixFileSystemInfo.GetFileSystemEntry(path);
			ufsf.FileAccessPermissions = (Mono.Unix.FileAccessPermissions)((6 << 6) | 0 | 0);
		}
		
		public void SavePasswords(XmlDocument doc)
		{
			if(doc == null)
				return;
			
			if(pwdBackend == null)
				use_keyring = false;
			else
			{
				try
				{
					if(use_keyring)
						pwdBackend.CheckKeyring();	
				}
				catch
				{
					use_keyring = false;
				}
			}
				
			if(use_keyring)
				pwdBackend.CleanUpItems();
			
			foreach(XmlNode node in doc.GetElementsByTagName("bookmark"))
			{
				bool success = false;
				
				string passwd = node.SelectSingleNode("password").InnerText;
				string user = node.SelectSingleNode("user").InnerText;
				string host = node.SelectSingleNode("host").InnerText;
				string protocol = node.SelectSingleNode("protocol").InnerText;
				string port = node.SelectSingleNode("port").InnerText;
				
				int keyid = -1;
				
				if(use_keyring)
				{
					keyid = pwdBackend.SetPwd(user, host, Convert.ToInt32(protocol), port, passwd, false);
					
					if(keyid > -1)
					{
						success = true;
					}
				}
				
				XmlNode pwdnode = node.SelectSingleNode("password");
				
				if(success)
				{
					XmlAttribute attr1 = doc.CreateAttribute("store");
					attr1.Value = "keyring";
					XmlAttribute attr2 = doc.CreateAttribute("keyid");
					attr2.Value = keyid.ToString();
					pwdnode.Attributes.Append(attr1);
					pwdnode.Attributes.Append(attr2);
					pwdnode.InnerText = string.Empty;
				}
				else
				{
					if(pwdnode.Attributes.Count > 0)
					{
						if(pwdnode.Attributes.GetNamedItem("store").Value == "keyring")
						{
							if(pwdnode.Attributes.Count > 1)
							{
								keyid = Convert.ToInt32(pwdnode.Attributes.GetNamedItem("keyid").Value);
							}
							string pwd = pwdBackend.GetPwd(keyid);
							pwdnode.Attributes.RemoveAll();
							pwdnode.InnerText = pwd;
							pwdBackend.DeletePassword(keyid);
						}
					}
				}
			}
			
		}
		
		public BookmarkItem RootItem {
		 	get {
		 		return rootItem;
		 	}
		}
	}
}
