using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Diagnostics;

namespace TFSWrappers
{
    public class WorkspaceWrapper /*: IDisposable*/
    {
        /// <summary>
        /// Constractor for creating a wrapper object using a TeamFoundationServer object.
        /// </summary>
        /// <param name="tfs">TeamFoundationServer object to use for creating the wrapper objects</param>
        /// <param name="workspaceName">Workspace name</param>
        public WorkspaceWrapper(TeamFoundationServer tfs, string workspaceName)
        {
            this.tfs = tfs;
            InitWrapper(workspaceName);
        }

        /// <summary>
        /// Constractor for creating a wrapper object. The TeamFoundationServer is created by the constractor 
        /// using the Team Foundation Server name.
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="workspaceName"></param>
        public WorkspaceWrapper(string serverName, string workspaceName)
        {
            tfs = TFSFunctions.GetServer(serverName);
            InitWrapper(workspaceName);
        }

        /// <summary>
        /// Free all objects
        /// </summary>
        /*public void Dispose()
        {
            if (ws != null)
            {
                ws = null;
            }
            if (vcs != null)
            {
                vcs = null;
            }
            if (tfs != null)
            {
                tfs = null;
            }
        }*/

        private TeamFoundationServer tfs;
        private VersionControlServer vcs;

        private Workspace ws;

        /// <summary>
        /// The Worksapce object of the wrapper.
        /// </summary>
        public Workspace WS
        {
            get { return ws; }
        }

        /// <summary>
        /// Inits the wrapper objects.
        /// </summary>
        /// <param name="workspaceName">Workspace name</param>
        private void InitWrapper(string workspaceName)
        {
            vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            ws = vcs.GetWorkspace(workspaceName, vcs.AuthenticatedUser);
        }

        /// <summary>
        /// Maps a file to a local path.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="fileLocalPath">The local path of the file. Like: C:\blabla\bla\bla.cs</param>
        public void MapFile(string fileServerPath, string fileLocalPath)
        {
            ws.Map(fileServerPath, fileLocalPath);
        }

        /// <summary>
        /// Clears a file mapping to a local path.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        public void ClearFileMapping(string fileServerPath)
        {
            if (ws.IsServerPathMapped(fileServerPath))
            {
                ws.DeleteMapping(ws.GetWorkingFolderForServerItem(fileServerPath));
            }
        }

        /// <summary>
        /// Gets a file latest version.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        public void GetLatestVersion(string fileServerPath)
        {
            GetRequest getRequest = new GetRequest(fileServerPath, RecursionType.None, VersionSpec.Latest);
            ws.Get(getRequest, GetOptions.Overwrite);
        }

        /// <summary>
        /// Gets a file latest version. Before the get maps the file to the local path and then unmaps it.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="fileLocalPath">The local path of the file. Like: C:\blabla\bla\bla.cs</param>
        public void GetLatestVersion(string fileServerPath, string fileLocalPath)
        {
            MapFile(fileServerPath, fileLocalPath);
            GetRequest getRequest = new GetRequest(fileServerPath, RecursionType.None, VersionSpec.Latest);
            ws.Get(getRequest, GetOptions.Overwrite);
        }

        /// <summary>
        /// Checks out a file.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="getLatestVersion">Defines if to get the file latest version from server before check out</param>
        /// <param name="overwrite">Defines if to overwrite a local version when taking latest version from server</param>
        public void CheckOutFile(string fileServerPath, bool getLatestVersion, bool overwrite)
        {
            if (getLatestVersion)
            {
                GetRequest getRequest = new GetRequest(fileServerPath, RecursionType.None, VersionSpec.Latest);
                if (overwrite)
                {
                    ws.Get(getRequest, GetOptions.Overwrite);
                }
            }
            ws.PendEdit(fileServerPath);
        }

        /// <summary>
        /// Checks out a file. Before the checkout maps the file to the local path.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="fileLocalPath">The local path of the file. Like: C:\blabla\bla\bla.cs</param>
        /// <param name="getLatestVersion">Defines if to get the file latest version from server before check out</param>
        /// <param name="overwrite">Defines if to overwrite a local version when taking latest version from server</param>
        public void CheckOutFile(string fileServerPath, string fileLocalPath, bool getLatestVersion, bool overwrite)
        {
            MapFile(fileServerPath, fileLocalPath);
            if (getLatestVersion)
            {
                GetRequest getRequest = new GetRequest(fileServerPath, RecursionType.None, VersionSpec.Latest);
                if (overwrite)
                {
                    ws.Get(getRequest, GetOptions.Overwrite);
                }
            }
            ws.PendEdit(fileServerPath);
        }

        /// <summary>
        /// Checks in a file.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="comment">The comment for the check in operation</param>
        public void CheckInFile(string fileServerPath, string comment)
        {
            PendingChange[] pendingChanges = ws.GetPendingChanges(fileServerPath);
            if (pendingChanges.Length > 0)
            {
                ws.CheckIn(pendingChanges, comment);
            }
        }

        /// <summary>
        /// Checks in a file. Can define if to clear the file mapping.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="comment">The comment for the check in operation</param>
        /// <param name="clearFileMapping">Define if to clear the file mapping</param>
        public void CheckInFile(string fileServerPath, string comment, bool clearFileMapping)
        {
            CheckInFile(fileServerPath, comment);
            if (clearFileMapping)
            {
                ClearFileMapping(fileServerPath);
            }
        }

        /// <summary>
        /// Undo check out a file.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        public void UndoCheckOutFile(string fileServerPath)
        {
            PendingChange[] pendingChanges = ws.GetPendingChanges(fileServerPath);
            if (pendingChanges.Length > 0)
            {
                ws.Undo(pendingChanges);
            }
        }

        /// <summary>
        /// Undo check out a file. Can define if to clear the file mapping.
        /// </summary>
        /// <param name="fileServerPath">The server path of the file. Like: $/blabla/bla/bla.cs</param>
        /// <param name="clearFileMapping">Define if to clear the file mapping</param>
        public void UndoCheckOutFile(string fileServerPath, bool clearFileMapping)
        {
            UndoCheckOutFile(fileServerPath);
            if (clearFileMapping)
            {
                ClearFileMapping(fileServerPath);
            }
        }

        public void Delete(string serverPath, string localPath, string comment)
        {
            MapFile(serverPath, localPath);
            ws.PendDelete(serverPath);
            PendingChange[] pendingChanges = ws.GetPendingChanges(serverPath);
            if (pendingChanges.Length > 0)
            {
                ws.CheckIn(pendingChanges, comment);
            }            
        }
    }
}
