//
// PermissionConfiguration.cs
//
// Author:
//       Carsten Sonne Larsen <cs@innolan.dk>
//
// Copyright (c) 2016 Carsten Sonne Larsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Collections.Generic;
using Ntp.Analyzer.Localize;
using Ntp.Config;
using Ntp.Interop;

namespace Ntp.Analyzer.Config.Root
{
    public sealed class PermissionConfiguration : ConfigurationBase
    {
        private PermissionConfiguration(
            string configName,
            int indentLevel,
            uint? appUserId,
            string appUserName,
            uint? userId,
            string userName,
            uint? groupId,
            string groupName,
            uint fileMode
            ) : base(configName, indentLevel)
        {
            this.appUserId = appUserId;
            this.appUserName = appUserName;
            this.userId = userId;
            this.userName = userName;
            this.groupId = groupId;
            this.groupName = groupName;
            this.fileMode = fileMode;
        }

        public const string Identifier = ConfigurationKeyword.Permission;

        private const int DefaultMode = 644;

        private static readonly String[] Params =
        {
            ConfigurationKeyword.Permission,
            ConfigurationKeyword.PermissionExecUser,
            ConfigurationKeyword.PermissionUser,
            ConfigurationKeyword.PermissionGroup,
            ConfigurationKeyword.PermissionMode
        };

        private readonly uint? appUserId;
        private readonly string appUserName;
        private readonly uint fileMode;
        private readonly uint? groupId;
        private readonly string groupName;
        private readonly uint? userId;
        private readonly string userName;

        protected override IEnumerable<Object> Items
        {
            get
            {
                var items = new List<object> {ConfigName};

                if ((appUserName ?? (object) AppUserId) != null)
                    items.Add(appUserName ?? (object) AppUserId);

                if ((userName ?? (object) userId) != null)
                    items.Add(userName ?? (object) userId);

                if ((groupName ?? (object) groupId) != null)
                    items.Add(groupName ?? (object) groupId);

                if (ShowDefault || (!ShowDefault && FileMode != DefaultMode))
                    items.Add(FileMode);

                return items.ToArray();
            }
        }

        public uint? AppUserId
        {
            get { return appUserId; }
        }

        public uint? UserId
        {
            get { return userId; }
        }

        public uint? GroupId
        {
            get { return groupId; }
        }

        public uint FileMode
        {
            get { return fileMode; }
        }

        public override string ToString()
        {
            var list = new List<String> {ConfigurationKeyword.Permission};

            if ((appUserName ?? (object) AppUserId) != null)
                list.Add(ConfigurationKeyword.PermissionExecUser);

            if ((userName ?? (object) userId) != null)
                list.Add(ConfigurationKeyword.PermissionUser);

            if ((groupName ?? (object) groupId) != null)
                list.Add(ConfigurationKeyword.PermissionGroup);

            if (ShowDefault || (!ShowDefault && FileMode != DefaultMode))
                list.Add(ConfigurationKeyword.PermissionMode);

            return list.Count != 1 ? ConfigText(list.ToArray(), Items) : null;
        }

        public static PermissionConfiguration Create(ConfigurationBlock config)
        {
            if (config == null)
            {
                config = new ConfigurationBlock();
            }

            Dictionary<String, String> options = GetOptions(Params, config);

            string execUserConfig = GetOptionString(options, ConfigurationKeyword.PermissionExecUser, Identifier, false);
            string userConfig = GetOptionString(options, ConfigurationKeyword.PermissionUser, Identifier, false);
            string groupConfig = GetOptionString(options, ConfigurationKeyword.PermissionGroup, Identifier, false);

            uint? execUserId;
            uint? userId;
            uint? groupId;

            if (execUserConfig == String.Empty)
            {
                execUserConfig = null;
                execUserId = null;
            }
            else
            {
                int parsedExecUserId;
                if (!Int32.TryParse(execUserConfig, out parsedExecUserId))
                {
                    execUserId = Permission.GetUserId(execUserConfig);
                    if (execUserId == null)
                    {
                        ConfigError(String.Format(ConfigurationMessage.UnknownUser, execUserConfig));
                    }
                }
                else
                {
                    execUserId = (uint?) parsedExecUserId;
                    execUserConfig = null;
                }
            }

            if (userConfig == String.Empty)
            {
                userConfig = null;
                userId = null;
            }
            else
            {
                int parsedUserId;
                if (!Int32.TryParse(userConfig, out parsedUserId))
                {
                    userId = Permission.GetUserId(userConfig);
                    if (userId == null)
                    {
                        ConfigError(String.Format(ConfigurationMessage.UnknownUser, userConfig));
                    }
                }
                else
                {
                    userId = (uint?) parsedUserId;
                    userConfig = null;
                }
            }

            if (groupConfig == String.Empty)
            {
                groupConfig = null;
                groupId = null;
            }
            else
            {
                int parsedGroupId;
                if (!Int32.TryParse(groupConfig, out parsedGroupId))
                {
                    groupId = Permission.GetGroupId(groupConfig);
                    if (groupId == null)
                    {
                        ConfigError(String.Format(ConfigurationMessage.UnknownGroup, groupConfig));
                    }
                }
                else
                {
                    groupId = (uint?) parsedGroupId;
                    groupConfig = null;
                }
            }

            return new PermissionConfiguration(
                GetOptionConfigName(options, Identifier, String.Empty, false),
                config.IndentLevel,
                execUserId,
                execUserConfig,
                userId,
                userConfig,
                groupId,
                groupConfig,
                (uint) GetOptionInteger(options, ConfigurationKeyword.PermissionMode, Identifier, false, DefaultMode)
                );
        }
    }
}