using System;
using System.Collections.Generic;
using System.Text;
using nft.framework.plugin;
using nft.framework;
using nft.core.structure;
using nft.framework.drawing;
using nft.core.view;
using nft.core.geometry;
using nft.util;
using System.Diagnostics;
using nft.core;
using System.Drawing;
using nft.core.graphics;
using ConditionedTextureSrc = nft.core.view.ConditionedResource<nft.core.graphics.TextureSrc>;

namespace nft.contributions.graphics {
    public class CtbStructureSkin : Contribution{
        protected ISiteDefiner site;
        protected DirectionalTextureSet textures;
        //protected 

        public static InterCardinalDirection ToDirection(int rotate_val) {
            // if the value is in between 1 to 4, it is recognized as multiplier to PI (1PI = 90degree).
            // if the value is greater than 4, it is recognized as a value in degree.
            if (Math.Abs(rotate_val) > 4) {
                // Normalize degree value into PI multiplier (form -3 to 3).
                rotate_val /= 90;
                rotate_val %= 4;                
            }
            // Normalize negative multiplier to positive.
            if (rotate_val < 0) rotate_val += 4;
            // Now, rotate_val have been converted to one of the values {0,1,2,3}.
            InterCardinalDirection ret = Direction.GetInterCardinalDirectionByZeroBaseIndex(rotate_val);
            return ret;
        }

        public static DirectionalTextureSet CreateDirectionalTextureSet(ParamsReader reader, ResourceParser<TextureSrc> parser) {
            ConditionedTextureSrc[] array = new ConditionedTextureSrc[4];
            foreach (ParamsReader pr in reader["sprite"].Each) {
                string[] args = pr["rotation"].InnerTextOr("0").Split(',');
                ConditionedTextureSrc _texture
                    = ConditionedResourceFactory.LoadAsConditiondResources<TextureSrc>(pr,parser);
                foreach (string arg in args) {
                    int rotate = int.Parse(arg);
                    InterCardinalDirection dir = CtbStructureSkin.ToDirection(rotate);
                    int idx = Direction.ToZeroBaseIndex(dir);
                    if (array[idx] != null) {
                        string msg = String.Format("Duplicate rotaion '{0}' in the series of sprite elements.");
                        throw new PluginXmlException(reader, msg);
                    }
                    array[idx] = _texture;
                }
            }
            if (array[0] == null) {
                throw new PluginXmlException(reader, "There mast be a 'sprite' element which rotation=0.");
            } else {

            }
            return DirectionalTextureSet.Create(array);
        }

        public CtbStructureSkin(Plugin owenr, ParamsReader reader)
            : base(owenr, reader) {
            site = ParseSite(reader);
            try {
                textures = CreateDirectionalTextureSet(reader, ParseTexture);
            } catch (ArgumentException ae){
                throw new PluginXmlException(this, reader, ae.Message);
            } catch (PluginXmlException pe) {
                pe.AttachContribution(this);
                throw;
            }
        }

        protected virtual ISiteDefiner ParseSite(ParamsReader reader) {
            ParamsReader pr2 = reader["site"];
            return new BasicSiteDefiner(pr2);
        }

        protected virtual TextureSrc ParseTexture(ParamsReader reader) {
            ParamsReader imageref = reader["image"]["ref"];
            if (imageref.IsNull) {
                throw new PluginXmlException(this, reader, "An 'ref' attribute under 'image' element is required.");
            }
            Rectangle rect = SiteDefiner.GetTextureRect(reader);
            CtbImageResource res = (CtbImageResource)GetOtherContribution(imageref.InnerText);            
            return new TextureSrc(res, rect);
        }

        public ISiteDefiner SiteDefiner {
            get {
                return site;
            }
        }

        public DirectionalTextureSet TextureSet {
            get {
                return textures;
            }
        }

        public StructureSkin NewSkin(InterCardinalDirection rotation_offset) {
            return new StructureSkin(this, rotation_offset);
        }

        public virtual ICatalogSource<ConditionedTextureSrc> GetCatalogSource(){
            return TextureSet;
        }
    }
}
