//-----------------------------------------------------------------------
// 
//  Copyright (C) Microsoft Corporation.  All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;

namespace CustomActions
{
    [RunInstaller(true)]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public sealed partial class SetSecurity : Installer
    {
        public SetSecurity()
        {
            InitializeComponent();
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            // Call the base implementation.
            base.Install(stateSaver);

            string allUsersString = this.Context.Parameters["allUsers"];
            string solutionCodeGroupName = this.Context.Parameters["solutionCodeGroupName"];
            string solutionCodeGroupDescription = this.Context.Parameters["solutionCodeGroupDescription"];
            string targetDir = this.Context.Parameters["targetDir"];
            string assemblyName = this.Context.Parameters["assemblyName"];
            string assemblyCodeGroupName = this.Context.Parameters["assemblyCodeGroupName"];
            string assemblyCodeGroupDescription = this.Context.Parameters["assemblyCodeGroupDescription"];

            // Note that a code group with solutionCodeGroupName name is created in the 
            // Install method and removed in the Rollback and Uninstall methods.
            // The solutionCodeGroupName must be a unique name to ensure that the 
            // correct code group is removed during Rollback and Uninstall.

            if (String.IsNullOrEmpty(solutionCodeGroupName))
                throw new InstallException("Cannot set the security policy. The specified solution code group name is not valid.");
            if (String.IsNullOrEmpty(solutionCodeGroupDescription))
                throw new InstallException("Cannot set the security policy. The specified solution code group description is not valid.");
            if (String.IsNullOrEmpty(targetDir))
                throw new InstallException("Cannot set the security policy. The specified target directory is not valid.");
            if (String.IsNullOrEmpty(assemblyName))
                throw new InstallException("Cannot set the security policy. The specified assembly name is not valid.");
            if (String.IsNullOrEmpty(assemblyCodeGroupName))
                throw new InstallException("Cannot set the security policy. The specified assembly code group name is not valid.");
            if (String.IsNullOrEmpty(assemblyCodeGroupDescription))
                throw new InstallException("Cannot set the security policy. The specified assembly code group description is not valid.");
            if (stateSaver == null)
                throw new ArgumentNullException("stateSaver");

            try
            {
                bool allUsers = String.Equals(allUsersString, "1");
                string assemblyPath = Path.Combine(targetDir, assemblyName);

                // Note that Install method may be invoked during Repair mode and the code group 
                // may already exist.
                // To prevent adding of another code group, remove the code group if it exists.
                try
                {
                    // The solutionCodeGroupName must be a unique name; otherwise, the method might delete wrong code group.
                    CaspolSecurityPolicyCreator.RemoveSecurityPolicy(allUsers, solutionCodeGroupName);
                }
                catch {}

                CaspolSecurityPolicyCreator.AddSecurityPolicy(
                    allUsers,
                    solutionCodeGroupName,
                    solutionCodeGroupDescription,
                    assemblyPath,
                    assemblyCodeGroupName,
                    assemblyCodeGroupDescription);

                // ライブラリのアクセス権を追加
                string[] libraryNames = new string[] {
                    "BTS.Redmine.dll", "Interop.CDO.dll", "Interop.ADODB.dll", "Interop.MSXML2.dll"
                };

                foreach ( string libraryName in libraryNames ) {
                    string libraryPath = Path.Combine( targetDir, libraryName );
                    CaspolSecurityPolicyCreator.AddSecurityPolicy(
                        allUsers,
                        solutionCodeGroupName,
                        solutionCodeGroupDescription,
                        libraryPath,
                        assemblyCodeGroupName,
                        assemblyCodeGroupDescription );
                }

                stateSaver.Add( "allUsers", allUsers );

            }
            catch (Exception ex)
            {
                throw new InstallException("Cannot set the security policy.", ex);
            }
        }

        public override void Rollback(System.Collections.IDictionary savedState)
        {
            // Call the base implementation.
            base.Rollback(savedState);

            // Check whether the "allUsers" property is saved.
            // If it is not set, the Install method did not set the security policy.
            if ((savedState == null) || (savedState["allUsers"] == null))
                return;

            // The solutionCodeGroupName must be a unique name; otherwise, the method might delete wrong code group.
            string solutionCodeGroupName = this.Context.Parameters["solutionCodeGroupName"];
            if (String.IsNullOrEmpty(solutionCodeGroupName))
                throw new InstallException("Cannot remove the security policy. The specified solution code group name is not valid.");

            try
            {
                bool allUsers = (bool) savedState["allUsers"];
                CaspolSecurityPolicyCreator.RemoveSecurityPolicy(allUsers, solutionCodeGroupName);
            }
            catch (Exception ex)
            {
                throw new InstallException("Cannot remove the security policy.", ex);
            }
        }


        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            // Call the base implementation.
            base.Uninstall(savedState);

            // Check whether the "allUsers" property is saved.
            // If it is not set, the Install method did not set the security policy.
            if ((savedState == null) || (savedState["allUsers"] == null))
                return;

            // The solutionCodeGroupName must be a unique name; otherwise, the method might delete wrong code group.
            string solutionCodeGroupName = this.Context.Parameters["solutionCodeGroupName"];
            if (String.IsNullOrEmpty(solutionCodeGroupName))
                throw new InstallException("Cannot remove the security policy. The specified solution code group name is not valid.");

            try
            {
                bool allUsers = (bool)savedState["allUsers"];
                CaspolSecurityPolicyCreator.RemoveSecurityPolicy(allUsers, solutionCodeGroupName);
            }
            catch (Exception ex)
            {
                // Note that throwing an exception might stop the uninstall process.
                // To inform the user and stop the uninstall process, throw an exception.
                // To continue the uninstall, do not throw the exception.
                throw new InstallException("Cannot remove the security policy.", ex);
            }
        }
    }
}