using System;
using System.Collections.Generic;
using System.Text;
using nft.framework.drawing;
using System.IO;
using System.Runtime.Serialization;
using System.Drawing;
using System.Diagnostics;
using nft.framework.util;

namespace nft.framework.plugin {
    class PluginImageManager {
        static private readonly Dictionary<String, ContributionImageRef> pathlist
            = new Dictionary<String, ContributionImageRef>();

        /// <summary>
        /// load image from the plugin directory.
        /// </summary>
        /// <param name="ctb">used to specify the owner plugin</param>
        /// <param name="relativePath">relative path for image, under the plugin dir</param>
        /// <returns></returns>
        public static ImageRef GetBundledImageRef(Contribution ctb, string relativePath) {
            string key = MakePluginPath(ctb, relativePath);
            ContributionImageRef ir;
            if (!pathlist.TryGetValue(key, out ir)) {
                ir = new ContributionImageRef(ctb, relativePath, false);
                pathlist.Add(key, ir);
            }
            return ir;
        }

        /// <summary>
        /// load image from data directory.
        /// files in the data directory should be created at the first boot.
        /// </summary>
        /// <param name="ctb">used to specify the data directroy</param>
        /// <param name="relativePath">relative path for image, under the contribution data dir</param>
        /// <returns></returns>
        public static ImageRef GetCachedImageRef(Contribution ctb, string relativePath) {
            string key = MakeCtbCachePath(ctb, relativePath);
            ContributionImageRef ir;
            if (!pathlist.TryGetValue(key, out ir)) {
                ir = new ContributionImageRef(ctb, relativePath, true);
                pathlist.Add(key, ir);
            }
            return ir;
        }

        public static void FreeIsolatedImages() {
            List<string> work = new List<string>();
            foreach (string key in pathlist.Keys) {
                ContributionImageRef ir = pathlist[key];
                if (ir.FreeIsIsolated()) {
                    work.Add(key);
                }
            }
            foreach (string key in work) {
                pathlist.Remove(key);
            }
        }

        protected internal static string MakePluginPath(Contribution ctb, string relative) {
            return Path.Combine(ctb.PluginDir, relative);
        }

        protected internal static string MakeCtbCachePath(Contribution ctb, string relative) {
            return Path.Combine(ctb.DataDirectory, relative);
        }
    }

    class ContributionImageRef : FileImageRef, ISerializable {
        protected readonly string cid;
        protected readonly string relPath;
        protected readonly string parentDir;

        internal protected static string ResolveParentDir(Contribution ctb, bool cached) {
            if (cached) {
                return ctb.DataDirectory;
            } else {
                return ctb.PluginDir;
            }
        }

        internal ContributionImageRef(Contribution ctb, string relativepath, bool cached) {
            this.cid = ctb.ID;
            this.relPath = relativepath;
            this.parentDir = ResolveParentDir(ctb, cached);
        }

        private ContributionImageRef(SerializationInfo info, StreamingContext context) {
            this.cid = info.GetString("cid");
            this.relPath = info.GetString("path");
            Contribution ctb  = PluginManager.theInstance.GetContribution(cid);
            bool cached = info.GetBoolean("cached");
            this.parentDir = ResolveParentDir(ctb, cached);
        }

        public override string FullPath {
            get { return Path.Combine(parentDir, relPath); }
        }

        internal bool FreeIsIsolated() {
            bool b = (RefCount > 0);
            if (!b) {
                base.ForceDispose();
            }
            return b;
        }

        #region ISerializable メンバ

        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.SetType(this.GetType());
			info.AddValue("cid",cid);
            info.AddValue("path", relPath);
            Contribution ctb = PluginManager.theInstance.GetContribution(cid);
            Boolean cached = !(ctb.PluginDir.Equals(parentDir));
            info.AddValue("cached", cached);
        }

        #endregion
    }
}
