"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DictionaryProperty = void 0;
const ExtensionMethods_1 = require("../ExtensionMethods");
const ComplexProperty_1 = require("./ComplexProperty");
const AltDictionary_1 = require("../AltDictionary");
const DictionaryKeyType_1 = require("../Enumerations/DictionaryKeyType");
const EwsServiceJsonReader_1 = require("../Core/EwsServiceJsonReader");
const EwsUtilities_1 = require("../Core/EwsUtilities");
const XmlAttributeNames_1 = require("../Core/XmlAttributeNames");
const XmlElementNames_1 = require("../Core/XmlElementNames");
const XmlNamespace_1 = require("../Enumerations/XmlNamespace");
/**
 * Represents a generic dictionary that can be sent to or retrieved from EWS.
 *
 * @typeparam   <TKey>      The type of key.
 * @typeparam   <TEntry>    The type of entry.
 */
class DictionaryProperty extends ComplexProperty_1.ComplexProperty {
    /**
     * @internal Initializes a new instance of the **DictionaryProperty** class.
     *
     * @param   {DictionaryKeyType}	dictionaryKeyType	Dictionary Key type, needed to workaround c# type checking of generics.
     */
    constructor(dictionaryKeyType) {
        super();
        this.dictionaryKeyType = DictionaryKeyType_1.DictionaryKeyType.EmailAddressKey;
        this.dictionaryKeyDelegate = (key) => { return this.dictionaryKeyTypeEnum[key]; };
        this.entries = new AltDictionary_1.Dictionary(this.dictionaryKeyDelegate);
        this.removedEntries = new AltDictionary_1.Dictionary(this.dictionaryKeyDelegate);
        this.addedEntries = [];
        this.modifiedEntries = [];
        this.dictionaryKeyType = dictionaryKeyType;
        this.dictionaryKeyTypeEnum = EwsUtilities_1.EwsUtilities.GetDictionaryKeyTypeEnum(this.dictionaryKeyType);
    }
    /**
     * Gets the entries.
     *
     * @value   The entries.
     */
    get Entries() {
        return this.entries;
    }
    /**
     * @internal Clears the change log.
     */
    ClearChangeLog() {
        this.addedEntries.splice(0);
        this.removedEntries.clear();
        this.modifiedEntries.splice(0);
        for (var entry of this.entries.Values) {
            entry.ClearChangeLog();
        }
    }
    /**
     * Determines whether this instance contains the specified key.
     *
     * @param   {TKey}      key   The key.
     * @return  {boolean}   true if this instance contains the specified key; otherwise, false.
     */
    Contains(key) {
        return this.Entries.containsKey(key);
    }
    /**
     * @internal Creates the entry.
     *
     * @return  {TEntry}  Dictionary entry.
     */
    CreateEntry() {
        return this.CreateEntryInstance();
    }
    /**
     * Entry was changed.
     *
     * @param   {}   complexProperty   The complex property.
     */
    EntryChanged(complexProperty) {
        var key = complexProperty.Key;
        if (this.addedEntries.indexOf(key) === -1 && this.modifiedEntries.indexOf(key) === -1) {
            this.modifiedEntries.push(key);
            this.Changed();
        }
    }
    /**
     * @internal Gets the name of the entry XML element.
     *
     * @param   {TEntry}    entry   The entry.
     * @return  {string}    XML element name.
     */
    GetEntryXmlElementName(entry) {
        return XmlElementNames_1.XmlElementNames.Entry;
    }
    /**
     * @internal Gets the index of the field.
     *
     * @param   {TKey}      key   The key.
     * @return  {string}    Key index.
     */
    GetFieldIndex(key) {
        return this.dictionaryKeyTypeEnum[key];
    }
    /**
     * @internal Gets the field URI.
     *
     * @return  {string}      Field URI.
     */
    GetFieldURI() {
        return null;
    }
    /**
     * @internal Add entry.
     *
     * @param   {TEntry}   entry   The entry.
     */
    InternalAdd(entry) {
        entry.OnChange.push(this.EntryChanged.bind(this));
        this.entries.Add(entry.Key, entry);
        this.addedEntries.push(entry.Key);
        this.removedEntries.remove(entry.Key);
        this.Changed();
    }
    /**
     * @internal Add or replace entry.
     *
     * @param   {TEntry}   entry   The entry.
     */
    InternalAddOrReplace(entry) {
        var oldEntry = { outValue: null };
        if (this.entries.tryGetValue(entry.Key, oldEntry)) {
            ExtensionMethods_1.ArrayHelper.RemoveEntry(oldEntry.outValue.OnChange, this.EntryChanged);
            entry.OnChange.push(this.EntryChanged.bind(this));
            if (this.addedEntries.indexOf(entry.Key) === -1) {
                if (this.modifiedEntries.indexOf(entry.Key) === -1) {
                    this.modifiedEntries.push(entry.Key);
                }
            }
            this.Changed();
        }
        else {
            this.InternalAdd(entry);
        }
    }
    /**
     * Remove entry based on key.
     *
     * @param   {TKey}   key   The key.
     */
    InternalRemove(key) {
        var entry = { outValue: null };
        if (this.entries.tryGetValue(key, entry)) {
            ExtensionMethods_1.ArrayHelper.RemoveEntry(entry.outValue.OnChange, this.EntryChanged);
            this.entries.remove(key);
            this.removedEntries.Add(key, entry.outValue);
            this.Changed();
        }
        ExtensionMethods_1.ArrayHelper.RemoveEntry(this.addedEntries, key);
        ExtensionMethods_1.ArrayHelper.RemoveEntry(this.modifiedEntries, key);
    }
    /**
     * @internal Loads service object from XML.
     *
     * @param   {any}				jsObject	Json Object converted from XML.
     * @param   {ExchangeService}	service	The service.
     */
    LoadFromXmlJsObject(jsonProperty, service) {
        if (jsonProperty[XmlElementNames_1.XmlElementNames.Entry]) {
            var entries = EwsServiceJsonReader_1.EwsServiceJsonReader.ReadAsArray(jsonProperty, XmlElementNames_1.XmlElementNames.Entry);
            for (var jsonEntry of entries) {
                var entry = this.CreateEntryInstance();
                entry.LoadFromXmlJsObject(jsonEntry, service);
                this.InternalAdd(entry);
            }
        }
    }
    /**
     * @internal Writes elements to XML.
     *
     * @param   {EwsServiceXmlWriter}   writer   The writer.
     */
    WriteElementsToXml(writer) {
        for (var keyValuePair of this.entries.Items) {
            keyValuePair.value.WriteToXml(writer, this.GetEntryXmlElementName(keyValuePair.value));
        }
    }
    /**
     * @internal Writes to XML.
     *
     * @param   {EwsServiceXmlWriter}   writer           The writer.
     * @param   {XmlNamespace}          xmlNamespace     The XML namespace.
     * @param   {string}                xmlElementName   Name of the XML element.
     */
    WriteToXml(writer, xmlElementName, xmlNamespace) {
        // Only write collection if it has at least one element.
        if (this.entries.Count > 0) {
            super.WriteToXml(writer, xmlElementName, xmlNamespace);
        }
    }
    /**
     * Writes the URI to XML.
     *
     * @param   {EwsServiceXmlWriter}   writer   The writer.
     * @param   {TKey}                  key      The key.
     */
    WriteUriToXml(writer, key) {
        writer.WriteStartElement(XmlNamespace_1.XmlNamespace.Types, XmlElementNames_1.XmlElementNames.IndexedFieldURI);
        writer.WriteAttributeValue(XmlAttributeNames_1.XmlAttributeNames.FieldURI, this.GetFieldURI());
        writer.WriteAttributeValue(XmlAttributeNames_1.XmlAttributeNames.FieldIndex, this.GetFieldIndex(key));
        writer.WriteEndElement();
    }
    /**
     * @internal Writes the update to XML.
     * ICustomUpdateSerializer.WriteSetUpdateToXml
     *
     * @param   {EwsServiceXmlWriter}   writer               The writer.
     * @param   {ServiceObject}         ewsObject            The ews object.
     * @param   {PropertyDefinition}    propertyDefinition   Property definition.
     * @return  {boolean}               True if property generated serialization.
     */
    WriteSetUpdateToXml(writer, ewsObject, propertyDefinition) {
        let tempEntries = [];
        for (let key of this.addedEntries) {
            tempEntries.push(this.entries.get(key));
        }
        for (let key of this.modifiedEntries) {
            tempEntries.push(this.entries.get(key));
        }
        for (let entry of tempEntries) {
            if (!entry.WriteSetUpdateToXml(writer, ewsObject, propertyDefinition.XmlElementName)) {
                writer.WriteStartElement(XmlNamespace_1.XmlNamespace.Types, ewsObject.GetSetFieldXmlElementName());
                this.WriteUriToXml(writer, entry.Key);
                writer.WriteStartElement(XmlNamespace_1.XmlNamespace.Types, ewsObject.GetXmlElementName());
                writer.WriteStartElement(XmlNamespace_1.XmlNamespace.Types, propertyDefinition.XmlElementName);
                entry.WriteToXml(writer, this.GetEntryXmlElementName(entry));
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
        for (let entry of this.removedEntries.Values) {
            if (!entry.WriteDeleteUpdateToXml(writer, ewsObject)) {
                writer.WriteStartElement(XmlNamespace_1.XmlNamespace.Types, ewsObject.GetDeleteFieldXmlElementName());
                this.WriteUriToXml(writer, entry.Key);
                writer.WriteEndElement();
            }
        }
        return true;
    }
    /**
     * @internal Writes the deletion update to XML.
     * ICustomUpdateSerializer.WriteDeleteUpdateToXml
     *
     * @param   {EwsServiceXmlWriter}   writer      The writer.
     * @param   {ServiceObject}         ewsObject   The ews object.
     * @return  {boolean}               True if property generated serialization.
     */
    WriteDeleteUpdateToXml(writer, ewsObject) {
        // Use the default XML serializer.
        return false;
    }
}
exports.DictionaryProperty = DictionaryProperty;
//# sourceMappingURL=DictionaryProperty.js.map