using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.IO.Packaging;

namespace Novacode
{
    /// <summary>
    /// Represents a Picture in this document, a Picture is a customized view of an Image.
    /// </summary>
    public class Picture: DocXElement
    {
        private const int EmusInPixel = 9525;

        internal Dictionary<PackagePart, PackageRelationship> picture_rels;
        
        internal Image img;
        private string id;
        private string name;
        private string descr;
        private int cx, cy;
        //private string fileName;
        private uint rotation;
        private bool hFlip, vFlip;
        private object pictureShape;
        private XElement xfrm;
        private XElement prstGeom;

        /// <summary>
        /// Remove this Picture from this document.
        /// </summary>
        public void Remove()
        {
            Xml.Remove();
        }

        /// <summary>
        /// Wraps an XElement as an Image
        /// </summary>
        /// <param name="document"></param>
        /// <param name="i">The XElement i to wrap</param>
        /// <param name="img"></param>
        internal Picture(DocX document, XElement i, Image img):base(document, i)
		{
		    picture_rels = new Dictionary<PackagePart, PackageRelationship>();
		    
		    this.img = img;
		
		    this.id =
		    (
		        from e in Xml.Descendants()
		        where e.Name.LocalName.Equals("blip")
		        select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value
		    ).SingleOrDefault();
		
		    if (this.id == null)
		    {
		        this.id =
		        (
		            from e in Xml.Descendants()
		            where e.Name.LocalName.Equals("imagedata")
		            select e.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value
		        ).SingleOrDefault();
		    }
		
		    this.name = 
		    (
		        from e in Xml.Descendants()
		        let a = e.Attribute(XName.Get("name"))
		        where (a != null)
		        select a.Value
		    ).FirstOrDefault();
		    
		    if (this.name == null)
		    {
		        this.name = 
		        (
		            from e in Xml.Descendants()
		            let a = e.Attribute(XName.Get("title"))
		            where (a != null)
		            select a.Value
		        ).FirstOrDefault();
		    }
		  
		    this.descr =
		    (
		        from e in Xml.Descendants()
		        let a = e.Attribute(XName.Get("descr"))
		        where (a != null)
		        select a.Value
		    ).FirstOrDefault();
		
		    this.cx = 
		    (
		        from e in Xml.Descendants()
		        let a = e.Attribute(XName.Get("cx"))
		        where (a != null)
		        select int.Parse(a.Value)
		    ).FirstOrDefault();
		    
		    if (this.cx == 0)
		    {
		        XAttribute style = 
		        (
		            from e in Xml.Descendants()
            let a = e.Attribute(XName.Get("style"))
		            where (a != null)
		            select a
		        ).FirstOrDefault();
		        
		        string fromWidth = style.Value.Substring(style.Value.IndexOf("width:") + 6);
		        var widthInt = ((double.Parse((fromWidth.Substring(0, fromWidth.IndexOf("pt"))).Replace(".", ","))) / 72.0) * 914400;
		        cx = System.Convert.ToInt32(widthInt);
		    }
		
		    this.cy = 
		    (
		        from e in Xml.Descendants()
		        let a = e.Attribute(XName.Get("cy"))
		        where (a != null)
		        select int.Parse(a.Value)
		    ).FirstOrDefault();
		    
		    if (this.cy == 0)
		    {
		        XAttribute style = 
		        (
		            from e in Xml.Descendants()
		            let a = e.Attribute(XName.Get("style"))
		            where (a != null)
		            select a
		        ).FirstOrDefault();
		        
		        string fromHeight = style.Value.Substring(style.Value.IndexOf("height:") + 7);
		        var heightInt = ((double.Parse((fromHeight.Substring(0, fromHeight.IndexOf("pt"))).Replace(".", ","))) / 72.0) * 914400;
		        cy = System.Convert.ToInt32(heightInt);
		    }
		
		    this.xfrm =
		    (
		        from d in Xml.Descendants()
		        where d.Name.LocalName.Equals("xfrm")
		        select d
		    ).SingleOrDefault();
		
		    this.prstGeom =
		    (
		        from d in Xml.Descendants()
		        where d.Name.LocalName.Equals("prstGeom")
		        select d
		    ).SingleOrDefault();
		
		    if (xfrm != null)
		        this.rotation = xfrm.Attribute(XName.Get("rot")) == null ? 0 : uint.Parse(xfrm.Attribute(XName.Get("rot")).Value);
		}

        private void SetPictureShape(object shape)
        {
            this.pictureShape = shape;

            XAttribute prst = prstGeom.Attribute(XName.Get("prst"));
            if (prst == null)
                prstGeom.Add(new XAttribute(XName.Get("prst"), "rectangle"));

            prstGeom.Attribute(XName.Get("prst")).Value = shape.ToString();
        }

        /// <summary>
        /// Set the shape of this Picture to one in the BasicShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the BasicShapes enumeration.</param>
        public void SetPictureShape(BasicShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the RectangleShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the RectangleShapes enumeration.</param>
        public void SetPictureShape(RectangleShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the BlockArrowShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the BlockArrowShapes enumeration.</param>
        public void SetPictureShape(BlockArrowShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the EquationShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the EquationShapes enumeration.</param>
        public void SetPictureShape(EquationShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the FlowchartShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the FlowchartShapes enumeration.</param>
        public void SetPictureShape(FlowchartShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the StarAndBannerShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the StarAndBannerShapes enumeration.</param>
        public void SetPictureShape(StarAndBannerShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// Set the shape of this Picture to one in the CalloutShapes enumeration.
        /// </summary>
        /// <param name="shape">A shape from the CalloutShapes enumeration.</param>
        public void SetPictureShape(CalloutShapes shape)
        {
            SetPictureShape((object)shape);
        }

        /// <summary>
        /// A unique id that identifies an Image embedded in this document.
        /// </summary>
        public string Id
        {
            get { return id; }
        }

        /// <summary>
        /// Flip this Picture Horizontally.
        /// </summary>
        public bool FlipHorizontal
        {
            get { return hFlip; }

            set
            {
                hFlip = value;

                XAttribute flipH = xfrm.Attribute(XName.Get("flipH"));
                if (flipH == null)
                    xfrm.Add(new XAttribute(XName.Get("flipH"), "0"));

                xfrm.Attribute(XName.Get("flipH")).Value = hFlip ? "1" : "0";
            }
        }

        /// <summary>
        /// Flip this Picture Vertically.
        /// </summary>
        public bool FlipVertical
        {
            get { return vFlip; }

            set
            {
                vFlip = value;

                XAttribute flipV = xfrm.Attribute(XName.Get("flipV"));
                if (flipV == null)
                    xfrm.Add(new XAttribute(XName.Get("flipV"), "0"));

                xfrm.Attribute(XName.Get("flipV")).Value = vFlip ? "1" : "0";
            }
        }

        /// <summary>
        /// The rotation in degrees of this image, actual value = value % 360
        /// </summary>
        public uint Rotation
        {
            get { return rotation / 60000; }

            set
            {
                rotation = (value % 360) * 60000;
                XElement xfrm =
                    (from d in Xml.Descendants()
                    where d.Name.LocalName.Equals("xfrm")
                    select d).Single();

                XAttribute rot = xfrm.Attribute(XName.Get("rot"));
                if(rot == null)
                    xfrm.Add(new XAttribute(XName.Get("rot"), 0));

                xfrm.Attribute(XName.Get("rot")).Value = rotation.ToString();
            }
        }

        /// <summary>
        /// Gets or sets the name of this Image.
        /// </summary>
        public string Name 
        { 
            get { return name; } 
            
            set 
            { 
                name = value;

                foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("name")))
                    a.Value = name;
            } 
        }

        /// <summary>
        /// Gets or sets the description for this Image.
        /// </summary>
        public string Description 
        { 
            get { return descr; } 
            
            set 
            { 
                descr = value;

                foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("descr")))
                    a.Value = descr;
            } 
        }

        ///<summary>
        /// Returns the name of the image file for the picture.
        ///</summary>
        public string FileName
        {
          get
          {
            return img.FileName;
          }
        }

        /// <summary>
        /// Get or sets the Width of this Image.
        /// </summary>
        public int Width 
        { 
            get { return cx / EmusInPixel; }
            
            set 
            { 
                cx = value;

                foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("cx")))
                    a.Value = (cx * EmusInPixel).ToString();
            } 
        }

        /// <summary>
        /// Get or sets the height of this Image.
        /// </summary>
        public int Height 
        { 
            get { return cy / EmusInPixel; }
            
            set 
            { 
                cy = value;

                foreach (XAttribute a in Xml.Descendants().Attributes(XName.Get("cy")))
                    a.Value = (cy * EmusInPixel).ToString();
            } 
        }

        //public void Delete()
        //{
        //    // Remove xml
        //    i.Remove();
   
        //    // Rebuild the image collection for this paragraph
        //    // Requires that every Image have a link to its paragraph

        //}
    }
}
