using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CssSpriteGenerator
{
    /// <summary>
    /// A CssImage represents a background image used in a specific CSS selector.
    /// </summary>
    /// 

    // TODO: when background-position-x and background-position-y become supported by Firefox,
    // drop BackgroundAlignment property.

    // TODO: get a CSS parser, so you can find images and selectors yourself.

    public class CssImage
    {
        /// <summary>
        /// The absolute url of the image
        /// </summary>
        public string ImageUrl { get; private set; }

        /// <summary>
        /// The CSS selector where the image is used.
        /// </summary>
        public string CssSelector { get; private set; }

        /// <summary>
        /// Specifies any restrictions on how the image can be combined with other images.
        /// For example HorizontalOnly for Repeat-Y background images.
        /// 
        /// This will be set to Null if there was no value in web.config.
        /// In that case, the property returns the default value, None.
        /// </summary>
        private CombineRestriction _combineRestriction = CombineRestriction.Null;
        public CombineRestriction CombineRestriction 
        { 
            get { return (_combineRestriction == CombineRestriction.Null) ? CombineRestriction.None : _combineRestriction; }
            private set { _combineRestriction = value; }
        }

        /// <summary>
        /// Specifies any restrictions on how the image needs to be aligned as a background image.
        /// 
        /// This is important with background images that are used with the sliding doors technique.
        /// These often need to be aligned to the right or bottom of the element that they provide
        /// background for.
        /// 
        /// The package needs this info (that is, it can't be inherited from the element in the same
        /// way as say the background color), because of a limitation in CSS. The package needs to override
        /// the background image url and position of the background image when it introduces the sprite, with css 
        /// such as:
        /// 
        /// background-image: url(gradient-hor-sprite.jpg);
        /// background-position: -20px 0px;
        /// 
        /// With sliding doors, the background image will only ever be combined horizontally or vertically
        /// with other background images. The other dimension needs to be inherited from the original element.
        /// You'd need background-position-x or background-position-y to override just one dimension, but these
        /// are not supported on Firefox!
        /// 
        /// Note that for example background-position: inherit -22px; will inherit both dimensions from the original
        /// element, ignoring the -22px.
        /// 
        /// This will be set to Null if there was no value in web.config.
        /// In that case, the property returns the default value, None.
        /// </summary>
        private Alignment _backgroundAlignment = Alignment.Null;
        public Alignment BackgroundAlignment 
        { 
            get { return (_backgroundAlignment == Alignment.Null) ? Alignment.None : _backgroundAlignment; }
            private set { _backgroundAlignment = value; }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="imageUrl"></param>
        /// <param name="cssSelector"></param>
        /// <param name="combineRestriction"></param>
        /// <param name="backgroundAlignment"></param>
        public CssImage(
            string imageUrl, string cssSelector, CombineRestriction combineRestriction, Alignment backgroundAlignment)
        {
            // Check consistency of BackgroundAlignment and CombineRestriction

            switch (backgroundAlignment)
            {
                case Alignment.Bottom:
                case Alignment.Top:
                    if (combineRestriction != CombineRestriction.HorizontalOnly)
                    {
                        ThrowInconsistencyException(
                            backgroundAlignment, CombineRestriction.HorizontalOnly, combineRestriction, imageUrl, cssSelector);
                    }
                    break;

                case Alignment.Left:
                case Alignment.Right:
                    if (combineRestriction != CombineRestriction.VerticalOnly)
                    {
                        ThrowInconsistencyException(
                            backgroundAlignment, CombineRestriction.VerticalOnly, combineRestriction, imageUrl, cssSelector);
                    }
                    break;
            }

            // ----------------

            this.ImageUrl = imageUrl;
            this.CssSelector = cssSelector;
            this.CombineRestriction = combineRestriction;
            this.BackgroundAlignment = backgroundAlignment;
        }

        private void ThrowInconsistencyException(
            Alignment alignmentUsed, 
            CombineRestriction combineTypeRestrictionExpected, CombineRestriction combineTypeRestrictionFound, 
            string imageUrl, string cssSelector)
        {
            string exceptionMessage = 
                string.Format(
                    "CssSpriteGenerator - For image {0} used with CSS selector {1}, the backgroundAlignment and " +
                    "combineRestriction are inconsistent. The backgroundAlignment is {2}. " +
                    "This requires a combineRestriction {3}, but it is {4}. " +
                    "If the background alignment is not important, set it to None. That allows you to use any combineRestriction.",
                    imageUrl, cssSelector, alignmentUsed.ToString(), 
                    CombineTypeRestriction_ToString(combineTypeRestrictionExpected), 
                    CombineTypeRestriction_ToString(combineTypeRestrictionFound));

            throw new Exception(exceptionMessage);
        }

        private string CombineTypeRestriction_ToString(CombineRestriction combineRestriction)
        {
            if (combineRestriction == CombineRestriction.Null)
            {
                return "not set";
            }

            return combineRestriction.ToString();
        }
    }
}
