//  Copyright (c) Microsoft Corporation.  All rights reserved.

namespace Microsoft.VisualStudio.TestTools.TestCaseMigrator
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.TeamFoundation;
    using Microsoft.TeamFoundation.TestManagement.Client;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;

    /// <summary>
    /// Wrapper over TCM Test Case
    /// </summary>
    internal class TestCase : IWorkItem
    {
        #region Fields

        private ITestManagementTeamProject m_tcmProject;

        private string m_testCaseTypeName;

        private string m_stepsFieldName;

        // ITestCase object to save workitem as TCM Testcase
        private ITestCase m_testCase;

        private string m_historyFieldValue;

        #endregion

        #region Constants

        // The character used by TCM for identifying parameter
        private const string TCMParameterizationCharacter = "@";

        // White space character
        private const string WhiteSpaceCharacter = " ";

        #endregion

        #region Constructor

        public TestCase(ITestManagementTeamProject project, string testCaseTypeName)
        {
            m_tcmProject = project;
            m_testCaseTypeName = testCaseTypeName;
        }

        #endregion

        #region Properties

        public object WorkItem
        {
            get
            {
                return m_testCase;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// creates TCM Testcase
        /// </summary>
        public void Create()
        {
            m_testCase = m_tcmProject.TestCases.Create(m_tcmProject.WitProject.WorkItemTypes[m_testCaseTypeName]);
        }

        /// <summary>
        /// Updates testcase's field with corresponding value
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value"></param>
        public void UpdateField(string fieldName, object value)
        {
            // If value is null then just take the default valuea nd return the default value
            if (value == null)
            {
                return;
            }

            List<SourceTestStep> sourceSteps = value as List<SourceTestStep>;

            // If the value is a List of test steps then Update th testcase with test steps
            if (sourceSteps != null)
            {
                m_stepsFieldName = fieldName;

                foreach (SourceTestStep sourceStep in sourceSteps)
                {
                    // Update the Test step's text with correct parameters
                    string title = sourceStep.title;
                    string expectedResult = sourceStep.expectedResult;

                    // Creating TCM Test Step and filling testcase with them
                    ITestStep step = m_testCase.CreateTestStep();
                    step.Title = title;
                    step.ExpectedResult = expectedResult;
                    if (sourceStep.attachments != null)
                    {
                        foreach (string filePath in sourceStep.attachments)
                        {
                            ITestAttachment attachment = step.CreateAttachment(filePath);
                            step.Attachments.Add(attachment);
                        }
                    }
                    m_testCase.Actions.Add(step);

                }
            }
            // else if it is a normal tfs field then just updates the tfs' testcase field
            else
            {
                if (fieldName == "History")
                {
                    m_historyFieldValue += value.ToString();
                }
                else if (m_testCase.WorkItem.Fields[fieldName].FieldDefinition.SystemType == typeof(DateTime))
                {
                    DateTime date;
                    if (DateTime.TryParse(value.ToString(), out date))
                    {
                        value = date;
                    }
                }
                else
                {
                    // Sets Value to Testcase's field
                    m_testCase.WorkItem.Fields[fieldName].Value = value;
                }
            }
        }

        /// <summary>
        /// Get corresponding Field value for field name
        /// </summary>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public object GetFieldValue(string fieldName)
        {
            if (fieldName == m_stepsFieldName)
            {
                List<SourceTestStep> sourceSteps = new List<SourceTestStep>();
                foreach (ITestAction action in m_testCase.Actions)
                {
                    ITestStep step = action as ITestStep;
                    if (step != null)
                    {
                        SourceTestStep sourceStep = new SourceTestStep();
                        sourceStep.title = step.Title;
                        sourceStep.expectedResult = step.ExpectedResult;
                        sourceStep.attachments = new List<string>();

                        foreach (var attachment in step.Attachments)
                        {
                            sourceStep.attachments.Add(attachment.Name);
                        }
                        sourceSteps.Add(sourceStep);
                    }
                }
                return sourceSteps;
            }
            else if (fieldName == "History")
            {
                if (m_testCase.WorkItem.Revisions.Count > 0)
                {
                    int revisonCount = m_testCase.WorkItem.Revisions.Count - 1;
                    return m_testCase.WorkItem.Revisions[revisonCount].Fields[fieldName].Value;
                }
                else
                {
                    return m_historyFieldValue;
                }
            }
            else
            {
                return m_testCase.WorkItem.Fields[fieldName].Value;
            }
        }

        /// <summary>
        /// Saves TCM tetcase
        /// </summary>
        public void Save()
        {
            try
            {
                if (!string.IsNullOrEmpty(m_historyFieldValue))
                {
                    if (m_historyFieldValue.Contains("<div><img src='"))
                    {
                        HistoryBuilder history = CreateHistoryBuilder();
                        m_testCase.Save();
                        m_testCase.WorkItem.Fields["History"].Value = history.Text;
                        m_testCase.Save();

                    }
                    else
                    {
                        m_testCase.WorkItem.Fields["History"].Value = m_historyFieldValue;
                        m_testCase.Save();
                    }
                }
                else
                {
                    m_testCase.Save();
                }
            }
            catch (TeamFoundationServerException)
            {
                string error = string.Empty;
                foreach (Field field in m_testCase.WorkItem.Fields)
                {
                    if (field.Status != FieldStatus.Valid)
                    {
                        error += "TFS Field: " + field.Name + "-->" + field.Status + "\n";
                    }
                }
                throw new TestCaseMigratorException(error, null, null);
            }
        }

        #endregion

        #region Private Methods

        private HistoryBuilder CreateHistoryBuilder()
        {
            HistoryBuilder history = new HistoryBuilder();

            while (m_historyFieldValue.Contains("<div><img src='"))
            {
                history.Append<string>(m_historyFieldValue.Substring(0, m_historyFieldValue.IndexOf("<div><img src='", StringComparison.Ordinal) + 15));

                m_historyFieldValue = m_historyFieldValue.Substring(m_historyFieldValue.IndexOf("<div><img src='", StringComparison.Ordinal) + 15);

                string attachmentPath = m_historyFieldValue.Substring(0, m_historyFieldValue.IndexOf("' /></div>", StringComparison.Ordinal));
                Attachment attachment = new Attachment(attachmentPath);
                m_testCase.WorkItem.Attachments.Add(attachment);
                history.Append<Attachment>(attachment);

                m_historyFieldValue = m_historyFieldValue.Substring(m_historyFieldValue.IndexOf("' /></div>", StringComparison.Ordinal));
            }
            history.Append<string>(m_historyFieldValue);
            return history;
        }

        #endregion
    }


    internal class HistoryBuilder
    {
        #region Fields

        private List<object> m_history = new List<object>();

        #endregion

        #region Properties

        public string Text
        {
            get
            {
                StringBuilder builder = new StringBuilder();
                foreach (object o in m_history)
                {
                    Attachment attachment = o as Attachment;
                    if (attachment != null)
                    {
                        builder.Append(attachment.Uri.ToString());
                    }
                    else
                    {
                        builder.Append(o.ToString());
                    }
                }
                return builder.ToString();
            }
        }

        #endregion

        #region public methods

        public void Append<Type>(Type part)
        {
            m_history.Add(part);
        }

        #endregion
    }


}
