﻿import {ArgumentException, ArgumentOutOfRangeException} from '../Exceptions/ArgumentException';
import {ArrayHelper} from '../ExtensionMethods';
import {EwsUtilities} from "../Core/EwsUtilities";
import {Strings} from "../Strings";
import {WellKnownFolderName} from "../Enumerations/WellKnownFolderName";

import {FolderId} from "./FolderId";
import {ComplexPropertyCollection} from "./ComplexPropertyCollection";
/**
 * Represents a collection of folder Ids.
 * 
 * @sealed
 */
export class FolderIdCollection extends ComplexPropertyCollection<FolderId> {

    /**
	 * @internal Initializes a new instance of the **FolderIdCollection** class.
	 */
    constructor();
    /**
     * @internal Initializes a new instance of the **FolderIdCollection** class.
     *
     * @param   {FolderId[]}   folderIds   The folder ids to include.
     */
    constructor(folderIds: FolderId[]);
    constructor(folderIds: FolderId[] = null) {
        super();
        if (folderIds != null) {
            folderIds.forEach((folderId) => this.InternalAdd(folderId));
        }
    }

    /**
     * Adds a folder Id to the collection.
     *
     * @param   {FolderId}   folderId   The folder Id to add.
     */
    Add(folderId: FolderId): void;
    /**
     * Adds a well-known folder to the collection.
     *
     * @param   {WellKnownFolderName}   folderName   The well known folder to add.
     * @return  {FolderId}      A FolderId encapsulating the specified Id.
     */
    Add(folderName: WellKnownFolderName): FolderId;
    Add(folderIdOrName: FolderId | WellKnownFolderName): void | FolderId {

        let folderId: FolderId = null;
        if (typeof folderIdOrName === 'number') {
            folderId = new FolderId(folderIdOrName);
            if (ArrayHelper.Find(this.Items, (item) => item.FolderName === folderIdOrName)) { //if (this.Contains(folderIdOrName)) { // can not use in JavaScript
                throw new ArgumentException(Strings.IdAlreadyInList, "folderName");
            }
        }
        else {

            EwsUtilities.ValidateParam(folderId, "folderId");
            folderId = folderIdOrName;
            if (this.Contains(folderId)) {
                throw new ArgumentException(Strings.IdAlreadyInList, "folderId");
            }
        }

        this.InternalAdd(folderId);

        return folderId;
    }

    /**
     * Clears the collection.
     */
    Clear(): void {
        this.InternalClear();
    }

    /**
     * @internal Instantiate the appropriate attachment type depending on the current XML element name.
     *
     * @param   {string}   xmlElementName   Name of the XML element.
     * @return  {FolderId}        FolderId.
     */
    CreateComplexProperty(xmlElementName: string): FolderId {
        return new FolderId();
    }

    /**
     * @internal Creates the default complex property.
     *
     * @return  {FolderId}      FolderId.
     */
    CreateDefaultComplexProperty(): FolderId {
        return new FolderId();
    }

    /**
     * @internal Gets the name of the collection item XML element.
     *
     * @param   {FolderId}  complexProperty   The complex property.
     * @return  {string}    XML element name.
     */
    GetCollectionItemXmlElementName(complexProperty: FolderId): string {
        return complexProperty.GetXmlElementName();
    }

    /**
     * Removes the specified folder Id from the collection.
     *
     * @param   {FolderId}   folderId   The folder Id to remove from the collection.
     * @return  {boolean}    True if the folder id was successfully removed from the collection, false otherwise.
     */
    Remove(folderId: FolderId): boolean;
    /**
     * Removes the specified well-known folder from the collection.
     *
     * @param   {WellKnownFolderName}   folderName   The well-knwon folder to remove from the collection.
     * @return  {boolean}               True if the well-known folder was successfully removed from the collection, false otherwise.
     */
    Remove(folderName: WellKnownFolderName): boolean;
    Remove(folderIdOrName: FolderId | WellKnownFolderName): boolean {
        if (typeof folderIdOrName === 'number') {
            // can not simply use InternalRemove as javascript does not have c# List functionality
            let index = ArrayHelper.IndexOf(this.Items, (item) => item.FolderName === folderIdOrName);
            if (index >= 0) {
                this.InternalRemoveAt(index);
                return true;
            }
        }
        else {
            EwsUtilities.ValidateParam(folderIdOrName, "folderId");

            return this.InternalRemove(folderIdOrName);
        }
        return false;
    }

    /**
     * Removes the folder Id at the specified index.
     *
     * @param   {number}   index   The zero-based index of the folder Id to remove.
     */
    RemoveAt(index: number): void {
        if (index < 0 || index >= this.Count) {
            throw new ArgumentOutOfRangeException("index", Strings.IndexIsOutOfRange);
        }

        this.InternalRemoveAt(index);
    }
}