//===============================================================================
// Microsoft patterns & practices
// Web Service Software Factory
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.SoftwareFactories.ServiceFactory.CommonHelpers;

namespace Microsoft.Practices.SoftwareFactories.ServiceFactory.Actions.CodeDom.Helpers
{
    /// <summary/>
    public class DirectedMappingMethod
    {
        private const string fromName = "from";
        private const string toName = "to";

        /// <summary/>
        public enum MappingDirection
        {
            /// <summary/>
            ForwardMap,
            /// <summary/>
            ReverseMap 
        }

        Type fromType;
        Type toType;
        ResultVariableDeclaration toDeclaration;
        MappingMethodDeclaration methodDeclaration;
        ReturnStatement returnStatement;
        List<MappingStatement> assignmentStatements = new List<MappingStatement>();
        List<UnmappedProperty> unmappedProperties = new List<UnmappedProperty>();

        /// <summary>
        /// Initializes a new instance of the <see cref="T:DirectedMappingMethod"/> class.
        /// </summary>
        /// <param name="fromType">From type.</param>
        /// <param name="toType">To type.</param>
        public DirectedMappingMethod(Type fromType, Type toType)
        {
            this.fromType = fromType;
            this.toType = toType;
        }

        /// <summary>
        /// Generates the specified mapped properties.
        /// </summary>
        /// <param name="mappedProperties">The mapped properties.</param>
        /// <param name="mappingDirection">The mapping direction.</param>
        public void Generate(MappedPropertyList mappedProperties, MappingDirection mappingDirection)
        {
            methodDeclaration = new MappingMethodDeclaration(fromType, fromName, toType);
            toDeclaration = new ResultVariableDeclaration(toType, toName);

            PublicPropertyList publicProperties = new PublicPropertyList(toType);

            foreach (MappedProperty mapping in mappedProperties)
            {
                PublicPropertyListItem source = (mappingDirection == MappingDirection.ForwardMap) ? mapping.FirstPropertyListItem : mapping.SecondPropertyListItem;
                PublicPropertyListItem target = (mappingDirection == MappingDirection.ForwardMap) ? mapping.SecondPropertyListItem : mapping.FirstPropertyListItem;
                if (source.CanMapTo(target))
                {
                    MappingStatement mappingStatement = new MappingStatement(source.Property, fromName, target.Property, toName);
                    assignmentStatements.Add(mappingStatement);
                    publicProperties.Remove(target);
                }
            }

            foreach (PublicPropertyListItem propertyItem in publicProperties)
            {
                unmappedProperties.Add(new UnmappedProperty(propertyItem.Property));
            }

            returnStatement = new ReturnStatement(toName);
        }

        /// <summary>
        /// Gets to declaration.
        /// </summary>
        /// <value>To declaration.</value>
        public ResultVariableDeclaration ToDeclaration { get { return toDeclaration; } }
        /// <summary>
        /// Gets the method declaration.
        /// </summary>
        /// <value>The method declaration.</value>
        public MappingMethodDeclaration MethodDeclaration { get { return methodDeclaration; } }
        /// <summary>
        /// Gets the return statement.
        /// </summary>
        /// <value>The return statement.</value>
        public ReturnStatement ReturnStatement { get { return returnStatement; } }
        /// <summary>
        /// Gets the assignment statements.
        /// </summary>
        /// <value>The assignment statements.</value>
        public List<MappingStatement> AssignmentStatements { get { return assignmentStatements; } }
        /// <summary>
        /// Gets the unmapped properties.
        /// </summary>
        /// <value>The unmapped properties.</value>
        public List<UnmappedProperty> UnmappedProperties { get { return unmappedProperties; } }
    }
}
