using System;
using System.IO;
using System.Text;
using System.Web.Caching;
using System.Web.Hosting;
using System.Web.Razor;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

namespace Muban.Compiler
{
    using Template;

    public class TemplateService : ITemplateService
    {

        protected virtual string GetCacheKey(string key, Type templateType = null)
        {
            if (templateType != null) return "Muban." + templateType.FullName + "_" + key.ToLower();
            return "Muban_" + key.ToLower();
        }

        public virtual ICompilerService GetCompilerService(RazorCodeLanguage language)
        {
            if (language is CSharpRazorCodeLanguage)
                return new CompilerService(new CSharpCodeProvider(), language);
            else if (language is VBRazorCodeLanguage)
                return new CompilerService(new VBCodeProvider(), language);
            return null;
        }

        protected virtual TemplateBase CreateTemplate(TextReader input, Type templateType, RazorCodeLanguage language)
        {
            using (var service = this.GetCompilerService(language))
            {
                var type = service.CompileType(new TypeContext
                {
                    TemplateType = templateType,
                    Input = input
                });
                return (TemplateBase)Activator.CreateInstance(type);
            }
        }

        public virtual string GetInclude(string fileName)
        {
            var key = this.GetCacheKey(fileName);
            var s = HostingEnvironment.Cache.Get(key) as string;
            if (s == null)
            {
                using (var reader = new StreamReader(fileName, Encoding.Default, true))
                    s = reader.ReadToEnd();
                HostingEnvironment.Cache.Insert(key, s, new CacheDependency(fileName), Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
            }
            return s;
        }

        public virtual IFileTemplate GetTemplate(string fileName, Type templateType, RazorCodeLanguage language, Action<object> activator)
        {
            var key = this.GetCacheKey(fileName, templateType);
            var template = HostingEnvironment.Cache.Get(key) as FileTemplate;
            if (template == null)
            {
                using (var reader = new StreamReader(fileName, Encoding.Default, true))
                    template = (FileTemplate)this.CreateTemplate(reader, templateType, language);
            }
            if (activator != null) activator(template);
            template.FileName = fileName;
            template.Activator = activator;
            template.Language = language;
            HostingEnvironment.Cache.Insert(key, template, new CacheDependency(fileName), Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
            return template;
        }

        public ITemplate Eval(string code, Type templateType, RazorCodeLanguage language, Action<object> activator)
        {
            using (var reader = new StringReader(code))
            {
                var template = this.CreateTemplate(reader, templateType, language);
                if (activator != null) activator(template);
                template.Activator = activator;
                template.Language = language;
                return template;
            }
        }
    }
}
