using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.Windows.Forms;

namespace Launcheroid
{
    public class Launcher
    {
        public string FILE_NAME = "links.lrd";
        private const string FILE_HEAD = "LnkrLnchr";

        private List<lLink> links = new List<lLink>();

        public void Clear()
        {
            links.Clear();
        }

        public void Add(string path)
        {
            lLink lnk = lLink.FromExternalFile(path);
            if (lnk == null)
                return;
            links.Add(lnk);
        }

        public void Del(lLink item)
        {
            links.Remove(item);
        }

        #region Load/Save
        public void Save()
        {
            FileStream fs = new FileStream(FILE_NAME, FileMode.Create, FileAccess.Write);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(Encoding.ASCII.GetBytes(FILE_HEAD));
            bw.Write((byte)3);
            bw.Write(links.Count);
            foreach (lLink lnk in links)
                lnk.SaveToStream(bw);
            bw.Close();
            fs.Close();
        }

        public void Load(string file)
        {
            Clear();
            if (file != null)
                FILE_NAME = file;
            if (!File.Exists(FILE_NAME))
                return;
            FileStream fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            try
            {
                if (Encoding.ASCII.GetString(br.ReadBytes(FILE_HEAD.Length)) != FILE_HEAD)
                    throw new Exception("El archivo no es compatible");
                int version = br.ReadByte();
                if (version > 3)
                    throw new Exception("Versión del archivo no soportada");
                if (version < 3)
                    br.ReadString();
                int cnt = br.ReadInt32();
                for (int i = 0; i < cnt; i++)
                    links.Add(lLink.FromStream(br, version));
            }
            finally
            {
                br.Close();
                fs.Close();
            }
        }

        public void Navigate(string path)
        {
            try
            {
                string[] dirs = Directory.GetDirectories(path);
                string[] fils = Directory.GetFiles(path);
                foreach (string dir in dirs)
                    links.Add(lLink.FromExternalFile(dir));
                foreach (string fil in fils)
                    links.Add(lLink.FromExternalFile(fil));
            }
            catch { };            
        }
        #endregion

        public lLink[] Links { get { return links.ToArray(); } }
    }

    public class lLink
    {
        private string name;
        private string path;
        private string dir;
        private string args;
        private bool isdir;
        private Image bmp;

        #region Constructors
        private lLink()
        {
        }

        public static lLink FromExternalFile(string path)
        {
            lLink result = new lLink();
            result.path = path;
            result.name = System.IO.Path.GetFileNameWithoutExtension(path);
            if (result.name.Length > 20)
                result.name = result.name.Substring(0, 20 - 3) + "...";
            result.isdir = Directory.Exists(path);
            if (!result.isdir)
            {
                result.args = "";
                result.dir = System.IO.Path.GetDirectoryName(path);
                if (result.dir == null)
                    result.dir = "";
                result.bmp = IconTool.GetFileIcon(path);
            }
            return result;
        }

        public static lLink FromStream(BinaryReader br, int version)
        {
            lLink result = new lLink();
            switch (version)
            {
                case 0:
                    result.LoadFromStreamV0(br);
                    break;
                case 1:
                    result.LoadFromStreamV1(br);
                    break;
                case 2:
                    result.LoadFromStreamV2(br);
                    break;
                case 3:
                    result.LoadFromStream(br);
                    break;
                default:
                    throw new Exception("Versión " + version + " no implementada");
            }
            return result;
        }
        #endregion

        #region Disk I/O
        internal void SaveToStream(BinaryWriter bw)
        {
            bw.Write(name);
            bw.Write(path);
            bw.Write(isdir);
            if (!isdir)
            {
                bw.Write(args);
                bw.Write(dir);
                if (bmp == null)
                    bw.Write(0);
                else
                {
                    MemoryStream ms = new MemoryStream();
                    bmp.Save(ms, ImageFormat.Png);
                    ms.Close();
                    byte[] idata = ms.ToArray();
                    ms = null;
                    bw.Write(idata.Length);
                    bw.Write(idata);
                }
            }
        }

        internal void LoadFromStreamV0(BinaryReader br)
        {
            name = br.ReadString();
            path = br.ReadString();
            args = br.ReadString();
            dir = "";
            isdir = Directory.Exists(path);
            byte[] idata = br.ReadBytes(br.ReadInt32());
            if (idata.Length > 0)
                bmp = ReadBitmap(idata);
            else
                bmp = null;
        }

        internal void LoadFromStreamV1(BinaryReader br)
        {
            name = br.ReadString();
            path = br.ReadString();
            args = br.ReadString();
            dir = System.IO.Path.GetDirectoryName(path);
            if (dir == null)
                dir = "";
            br.ReadBoolean();
            byte[] idata = br.ReadBytes(br.ReadInt32());
            if (idata.Length > 0)
                bmp = ReadBitmap(idata);
            else
                bmp = null;
            isdir = Directory.Exists(path);
        }

        internal void LoadFromStreamV2(BinaryReader br)
        {
            name = br.ReadString();
            path = br.ReadString();
            args = br.ReadString();
            dir = br.ReadString();
            br.ReadBoolean();
            byte[] idata = br.ReadBytes(br.ReadInt32());
            if (idata.Length > 0)
                bmp = ReadBitmap(idata);
            else
                bmp = null;
            isdir = Directory.Exists(path);
        }

        internal void LoadFromStream(BinaryReader br)
        {
            name = br.ReadString();
            path = br.ReadString();
            isdir = br.ReadBoolean();
            if (!isdir)
            {
                args = br.ReadString();
                dir = br.ReadString();
                byte[] idata = br.ReadBytes(br.ReadInt32());
                if (idata.Length > 0)
                    bmp = ReadBitmap(idata);
                else
                    bmp = null;
            }
        }

        private static Image ReadBitmap(byte[] idata)
        {
            MemoryStream ms = new MemoryStream(idata);
            Image bmp = Image.FromStream(ms);
            if (bmp == null)
                return null;
            if (bmp.Width == 48 && bmp.Height == 48)
                return bmp;
            return bmp.GetThumbnailImage(48, 48, null, IntPtr.Zero);
        }
        #endregion

        #region Launch
        public bool Open()
        {
            try
            {
                if (isdir)
                {
                    Form1 subf = new Form1(path);
                    return subf.ShowDialog() == DialogResult.OK;
                }
                else
                {
                    ProcessStartInfo psi = new ProcessStartInfo();
                    psi.FileName = path;
                    psi.Arguments = args;
                    psi.ErrorDialog = true;
                    psi.WorkingDirectory = dir;
                    Process.Start(psi);
                    return true;
                }

            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, e.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return false;
        }
        #endregion

        public Image Icon { get { return bmp; } set { bmp = value; } }
        public string Name { get { return name; } set { name = value; } }
        public string Path { get { return path; } set { path = value; } }
        public string Args { get { return args; } set { args = value; } }
        public string Dir { get { return dir; } set { dir = value; } }
        public bool Navigate { get { return isdir; } }
    }
}
