/*
 * Copyright (C) 1998-2017 by Northwoods Software Corporation
 * All Rights Reserved.
 *
 * GoCloudStorage.js
*/

import * as go from "../../release/go";
import {Promise} from "es6-promise";

/**
 * A simple interface containing basic information about a diagram saved to a storage service. Guarantees the existence of file id, name, and path. 
 * <p>DiagramFiles are used as a minimal representation of files stored in data. {@link GoCloudStorage.currentDiagramFile}. 
 * {@link GoCloudStorage.save}, {@link GoCloudStorage.load}, {@link GoCloudStorage.remove}, and {@link GoCloudStorage.create} all return Promises which resolve with
 * DiagramFiles containing minimal data about the saved / loaded / removed / created file in storage. </p>
 * @category Storage
 */
export interface DiagramFile {
    /**
     * The storage-given ID of the diagram file. This is usually a lengthy alphanumeric string. 
     * <p><b>Note</b>: In the case of files saved to / loaded from Local Storage with {@link GoLocalStorage},ID is the same as the name of the file.
     */
    id: string;
    /**
     * The name of the diagram file in storage. This is assigned by the user during {@link GoCloudStorage.save}.
     */
    name: string;
    /**
     * The path of the diagram file in storage. Rules for valid path syntax by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     */
    path: string;
    /**
     * @private 
     * @hidden
     * token is sometimes necesary for {@link GoOneDrive}. This is an access token given by the <a href="https://dev.onedrive.com/sdk/js-v72/js-picker-overview.htm">
     * Microsoft OneDrive Filepicker</a> allowing read / write on a specific drive file.
     * No other {@link GoCloudStorage} subclasses use it. It is unlikely one will use this field without editing source code.
     */
    token?: string, 
    /**
     * @private
     * @hidden
     * parentReference is sometimes necesary for {@link GoOneDrive}. It is the 
     * <a href="https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/resources/itemreference"> parent information</a> 
     * of a Microsoft OneDrive item, if the item has a parent.
     * No other {@link GoCloudStorage} subclasses use it. It is unlikely one will use this field without editing source code.
     */
    parentReference?: Object
}

/**
 * @private 
 * @hidden
 * A simple interface acting as a wrapper for a Promise that gurantees the existence of the promise field.
 * DeferredPromise is important in that it allows for a Promise to be returned by one function and resolved within another. 
 * You may call <code>.resolve</code> and <code>.reject</code> on this field as you may a standard ES6 Promise. After resolving / rejecting
 * deferredPromise.promise, it is recommended you reset it by calling {@link GoCloudStorage.makeDeferredPromise}. Example:</p>
 * 
 * ```js
 * 
 * // function a returns the "promise" field of deferredPromise
 * function a () {
 *      return gcs.deferredPromise.promise
 * }
 * 
 * // function b resolves the "promise" field of deferredPromise and resets it
 * function b () {
 *      gcs.deferredPromise.promise.resolve("Promise resolved"); // resolve
 *      gcs.deferredPromise.promise = gcs.makeDeferredPromise(); // reset
 * }
 * 
 * a(); // return deferredPromise.promise
 * b(); // b is called after a (and before anything else can resolve deferredPromise.promise), so b resolves deferredPromise.promise
 * 
 * ``` 
 */
export interface DeferredPromise {
    promise: any; // this really isn't "any", it's an ES6 Promise, but declaring it as Promise<any> removes .resolve() functionality???
}

/**
 * An abstract class for storing GoJS <a href="http://gojs.net/latest/api/symbols/Diagram.html">Diagram</a> 
 * <a href="http://gojs.net/latest/api/symbols/Model.html">models</a> in various cloud storage services.
 * <p>GoCloudStorage is never used on its own. Its subclasses can be used to manage diagram model storage programatically, 
 * or any subset of GoCloudStorage subclasses can be bundled and used graphically with the {@link GoCloudStorageManager}.</p>
 * <p><strong>Note</strong>: With the exception of {@link GoLocalStorage}, all GoCloudStorage subclasses must be used in pages served 
 * on a web server.</p>
 * @category Storage
 */
export class GoCloudStorage {

    private _managedDiagrams: go.Diagram[];
    private _clientId: string;
    private _isAutoSaving: boolean; 
    private _currentDiagramFile: DiagramFile;
    private _ui: HTMLElement;
    private _defaultModel: string;
    /**
     * @private
     * @hidden
     */
    protected _serviceName: string;
    /**
     * @private
     * @hidden
     */
    protected _deferredPromise: DeferredPromise;
    private _iconsRelativeDirectory: string;

    /**
     * @constructor
     * @param {go.Diagram|go.Diagram[]} managedDiagrams An array of GoJS <a href="http://gojs.net/latest/api/symbols/Diagram.html">Diagrams</a> whose model(s) will be saved to
     * / loaded from a cloud storage service. Can also be a single Diagram. 
     * @param {string} clientId The client ID of the cloud storage application to use (given by the cloud storage service to developer). Not needed for all subclasses.
     * @param {string} defaultModel String representation of the default model data for new diagrams. If this is null, default new diagrams will be empty. 
     * Usually a value given by calling <a href="https://gojs.net/latest/api/symbols/Model.html#toJson">.toJson()</a> on a GoJS Diagram's Model. 
     * @param {string} iconsRelativeDirectory The directory path relative to the page in which this instance of GoCloudStorage exists, in which
     * the storage service brand icons can be found. The default value is "../goCloudStorageIcons/".
    */
    constructor(managedDiagrams: go.Diagram|go.Diagram[], defaultModel?: string, clientId?: string, iconsRelativeDirectory?: string) {
        if (managedDiagrams instanceof go.Diagram) managedDiagrams = [managedDiagrams];
        this._managedDiagrams = managedDiagrams;
        this._currentDiagramFile = { name: null, id: null, path: null };
        this._isAutoSaving = true;
        if (defaultModel) this._defaultModel = defaultModel;
        if (clientId) this._clientId = clientId;
        else clientId = null;
        this._iconsRelativeDirectory = (!!iconsRelativeDirectory) ? iconsRelativeDirectory : "../goCloudStorageIcons/";
        
        const menu = document.createElement('div');
        menu.className = 'goCustomFilepicker';
        menu.style.visibility = 'hidden';
        document.getElementsByTagName('body')[0].appendChild(menu); 
        this._ui = menu;
        this._deferredPromise = { promise: this.makeDeferredPromise() };

        // enable autosaving capability
        function addAutoSave(d: go.Diagram) {
            d.addModelChangedListener(function (e: go.ChangedEvent) {
                if (e.isTransactionFinished && storage.isAutoSaving && e.oldValue !== "") {
                    if (storage.currentDiagramFile.name) {
                        storage.save();
                    }
                }
            });
        }

        const d = this.managedDiagrams;
        const storage = this;
        if (d instanceof go.Diagram) {
            addAutoSave(d);
        } else for (let i = 0; i < d.length; i++) {
            addAutoSave(d[i]);
        }
    }

    /** 
     * Get / set the GoJS <a href="http://gojs.net/latest/api/symbols/Diagram.html">Diagram</a>s associated with this instance of GoCloudStorage. 
     * Set with a parameter during construction. 
     * @function.
     * @return {go.Diagram[]}
    */
    get managedDiagrams(): go.Diagram[] { return this._managedDiagrams }
    set managedDiagrams(value: go.Diagram[]) { this._managedDiagrams = value }
    
    /**
     * Get / set the defaultModel data for the app used by an instance of GoCloudStorage. defaultModel is used when creating new diagrams. See {@link create}.
     * @function.
     * @return {string}
     */
    get defaultModel(): string { return this._defaultModel }
    set defaultModel(value: string) { this._defaultModel = value }

    /**
     * Get / set iconsRelativeDirectory, the directory path relative to the page in which this instance of GoCloudStorage exists, in which
     * the storage service brand icons can be found. The default value is "../goCloudStorageIcons/".
     * @function.
     * @return {string}
     */
    get iconsRelativeDirectory(): string { return this._iconsRelativeDirectory }
    set iconsRelativeDirectory(value: string) { this._iconsRelativeDirectory = value }

    /**
     * Get the clientId for the app using the cloud storage service. This is usually given by the cloud storage provider's dev console or similar. 
     * Set with a parameter during construction.
     * @function.
     * @return {string}
    */ 
    get clientId(): string { return this._clientId }

    /**
     * Get or set the currently open {@link DiagramFile}. By default, currentDiagramFile is set when a file is loaded from storage, saved to storage 
     * (if saved to a different path from the currentDiagramFile.path), or deleted from storage (if the deleted file is the currently open one). 
     * The default value is a {@link DiagramFile} with null id, name, and path values. 
     * @function.
     * @return {Object}
    */
    get currentDiagramFile(): DiagramFile { return this._currentDiagramFile }
    set currentDiagramFile(value: DiagramFile) { this._currentDiagramFile = value }

    /**
     * Get or set isAutoSaving property. If true, the {@link managedDiagrams} will be saved to storage after every 
     * <a href="https://gojs.net/latest/api/symbols/Transaction.html"> Transaction</a> (only if {@link currentDiagramFile} holds a non-null path value).
     * Additionally, if isAutoSaving is true, users will be prompted to save newly created diagrams when created with {@link create}. 
     * The default value for isAutoSaving is <code>true</code>. 
     * @function.
     * @return {boolean}
    */
    get isAutoSaving(): boolean { return this._isAutoSaving }
    set isAutoSaving(value: boolean) { this._isAutoSaving = value }

    /**
     * Get the name of the cloud storage service being used; i.e. "Dropbox"
     * @function.
     * @return {string}
     */
    get serviceName(): string { return this._serviceName };

    /**
     * Get the UI element associated with this instance of GoCloudStorage. This is a custom filepicker window for {@link GoDropBox} and 
     * {@link GoLocalStorage}. It is a save prompt for {@link GoOneDrive} and {@link GoGoogleDrive} (both these classes use third party 
     * UI for storage navigation, provided by Microsoft and Google, respectively). The UI element is created during construction. 
     * @function.
     * @return {HTMLElement}
    */
    get ui(): HTMLElement { return this._ui }

    /**
     * <p>Get / set deferredPromise property. This is a special property that is simply an Object with a "promise" field, which contains an 
     * ES6 <a href="http://es6-features.org/#PromiseUsage">Promise</a>. DeferredPromise is important in that it allows for a Promise to be 
     * returned by one function and resolved within another. You may call <code>.resolve</code> and <code>.reject</code> on this field as you may 
     * a standard ES6 Promise. After resolving / rejecting deferredPromise.promise, it is recommended you reset it by calling {@link makeDeferredPromise}. Example:</p>
     * 
     * ```js
     * 
     * // function a returns the "promise" field of deferredPromise
     * function a () {
     *      return gcs.deferredPromise.promise
     * }
     * 
     * // function b resolves the "promise" field of deferredPromise and resets it
     * function b () {
     *      gcs.deferredPromise.promise.resolve("Promise resolved"); // resolve
     *      gcs.deferredPromise.promise = gcs.makeDeferredPromise(); // reset
     * }
     * 
     * a(); // return deferredPromise.promise
     * b(); // b is called after a (and before anything else can resolve deferredPromise.promise), so b resolves deferredPromise.promise
     * 
     * ``` 
     * @function.
     * @return {Object}
    *
    get deferredPromise(): DeferredPromise { return this._deferredPromise }
    set deferredPromise(value: DeferredPromise) { this._deferredPromise = value }*/

    /**
     * <p>Explicitly authorize a currently-signed in user of the storage service to use the application associated with this 
     * instance of GoCloudStorage (via {@link clientId}. If no currently signed-in user exists, prompt user to sign into their account, then authorize that account.</p>
     * <p><b>Note:</b> Authorization does not occur (and is not possible or necessary) with {@link GoLocalStorage}. Instead, 
     * {@link GoLocalStorage.authorize} ensures localStorage exists in the browser.</p>
     * @param {boolean} refreshToken Whether to get a new access token (true) or try to find / use an existing one. Exact behavior varies
     * from subclass to subclass. See:
     * <ul>
     *  <li>{@link GoLocalStorage.authorize}</li>
     *  <li>{@link GoDropBox.authorize}</li>
     *  <li>{@link GoGoogleDrive.authorize}</li>
     *  <li>{@link GoOneDrive.authorize}</li>
     * </ul> 
     * @return {Promise<any>} Returns a Promise that resolves with a boolean stating whether authorization was succesful (true) or failed (false).
    */
    public authorize(refreshToken: boolean = false) {
        return new Promise(function(resolve: Function, reject: Function){
            console.error("authorize not implemented");
            reject(false);
        });
    }

    /**
     * @private
     * @hidden
     * Returns a new {@link DeferredPromise}. Use this method to reset {@link deferredPromise}.promise property after deferredPromise.promise has been resolved. For example:
     * 
     * ```js
     * 
     * // function a returns the "promise" field of deferredPromise
     * function a () {
     *      return gcs.deferredPromise.promise
     * }
     * 
     * // function b resolves the "promise" field of deferredPromise and resets it
     * function b () {
     *      gcs.deferredPromise.promise.resolve("Promise resolved"); // resolve
     *      gcs.deferredPromise.promise = gcs.makeDeferredPromise(); // reset
     * }
     * 
     * a(); // return deferredPromise.promise
     * b(); // b is called after a (and before anything else can resolve deferredPromise.promise), so b resolves deferredPromise.promise
     * 
     * ``` 
     * @return {Promise<Object>}
    */
    public makeDeferredPromise(): Promise<Object> {
        let res: Function, rej: Function;
        let promise: any = new Promise((resolve: Function, reject: Function) => {
            res = resolve;
            rej = reject;
        });
        promise.resolve = res;
        promise.reject = rej;

        return promise;
    }

    /**
     * Get information about the currently logged in user. This information varies from subclass to subclass. For more info, see:
     * <ul>
     *  <li>{@link GoLocalStorage.getUserInfo}</li>
     *  <li>{@link GoDropBox.getUserInfo}</li>
     *  <li>{@link GoGoogleDrive.getUserInfo}</li>
     *  <li>{@link GoOneDrive.getUserInfo}</li>
     * </ul>  
     * @return {Promise<any>} Returns a Promise that resolves with information about the currently logged in user
    */
    public getUserInfo() {
        return new Promise(function(resolve: Function, reject: Function){
            reject("getUserInfo not implemented");
        });
    }

    /**
     * Hide the {@link ui} element associated with this instance of GoCloudStorage. Used in some UI element onclicks.
     * @param {boolean} isActionCanceled If action (save, delete, load) is canceled, resolve Promise (returned previously in 
     * {@link showUI}) with a 'Canceled' notification. Default value is false.
    */
    public hideUI(isActionCanceled: boolean = false) {
        const storage = this;
        storage.ui.style.visibility = 'hidden';
        if (isActionCanceled) {
            var action = document.getElementById('actionButton').innerHTML;
            storage._deferredPromise.promise.resolve(action + ' canceled by user');
            storage._deferredPromise.promise = storage.makeDeferredPromise();
        }
    }

    /**
     * Check whether a file exists at a given path.
     * @param {string} path A valid filepath. What is meant by this varies from subclass to subclass. Rules for valid filepaths by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {Promise<boolean>} Returns a Promise that resolves with a boolean stating whether a file exists at a given path.
    */
    public checkFileExists(path: string) {
        return new Promise(function(resolve: Function, reject: Function){
            reject("checkFileExists not implemented");
        });    
    }

    /**
     * Get the file at a given path in storage. The exact file data given varies from storage service 
     * to storage service, though all include name, path, id data. The exact syntax of these data fields may vary. 
     * See subclass-specific documentation for more details.
     * <ul>
     *  <li>{@link GoLocalStorage.getFile}</li>
     *  <li>{@link GoDropBox.getFile}</li>
     *  <li>{@link GoGoogleDrive.getFile}</li>
     *  <li>{@link GoOneDrive.getFile}</li>
     * </ul>
     * @param {string} path A valid filepath. What is meant by this varies from subclass to subclass. Rules for valid filepaths by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {Promise<any>} Return a Promise that resolves with the file at a given path in storage(or null).
    */
    public getFile(path: string) {
        return new Promise(function(resolve: Function, reject: Function){
            throw Error("getFile not implemented");
        });
    }

    /**
     * Show the {@link ui} element associated with this instance of GoCloudStorage.
     * @param {string} action Clarify what action is being done after file selection. Acceptable values: Save, Delete, Load
     * @return {Promise} Returns a Promise that resolves (in {@link save}, {@link load}, or {@link remove} with an {@link DiagramFile} 
     * representing the saved/loaded/deleted file
    */
    public showUI(action: string) {
        return new Promise(function(resolve: Function, reject: Function){
            throw Error("showUI not implemented");
        });
    }

    /**
     * Set each of {@link managedDiagrams}' .model to {@link defaultModel} (if defaultModel is null, 
     * each model will be set to a new <a href="https://gojs.net/latest/api/symbols/GraphLinksModel.html">GraphLinksModel</a> by default).
     * If {@link isAutoSaving} is true and no path parameter is supplied, users will be immediately prompted to save their new diagrams to cloud storage. 
     * @param {string} path If a valid filepath is supplied, save each of {@link managedDiagrams}' model data to this path. No UI of any sort appears. 
     * What is meant by "valid filepath" varies from subclass to subclass. Rules for valid filepaths by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {boolean} Returns a Promise that resolves with a {@link DiagramFile} representing the newly created file. 
    */
    public create(path?: string) {
        const storage = this;
        const diagrams = storage.managedDiagrams;
        return new Promise(function (resolve: Function, reject: Function) {
            storage.currentDiagramFile = { name: null, id: null, path: null };
            function makeNewDiagram(d: go.Diagram) {
                if (storage.defaultModel) d.model = go.Model.fromJson(JSON.parse(storage.defaultModel));
                else d.model = new go.GraphLinksModel;
            }
            if (storage.managedDiagrams instanceof go.Diagram) {
                makeNewDiagram(storage.managedDiagrams);
            } else for (let i = 0; i < storage.managedDiagrams.length; i++) {
                makeNewDiagram(storage.managedDiagrams[i]);
            }
            if (storage.isAutoSaving) {
                if (path) {
                    resolve(storage.save(path));
                } else resolve(storage.saveWithUI());
            } else resolve("New diagram created.") // no prompt to save
        });
    }

    /**
     * @private
     * @hidden
     * Returns the data to save to storage. This is a string representation of a JSON-like object.
     * Keys are the div IDs of the diagrams being saved. Values are the model.toJson() values for those diagrams.
     * @return {string}
     */
    protected makeSaveFile() {
        let item: string = '{\n';
        const storage = this;
        if (storage.managedDiagrams.length == 0) return;
        for (let i = 0; i < storage.managedDiagrams.length; i++) {
            let diagram: go.Diagram = storage.managedDiagrams[i];
            let div: string = diagram.div.id;
            item +=  '"' + div + '"' + ': ' + diagram.model.toJson();
            if (i+1 !== storage.managedDiagrams.length) item += ',\n';
        }
        
        item += '\n}';
        return item;
    }

    /**
     * @private
     * @hidden
     * Loads all models in a saved file to their respective diagrams
     */
    protected loadFromFileContents(fileContents: string) {
        const storage = this;
        let models = JSON.parse(fileContents);
        for (let divId in models) {
            let model = models[divId];
            let div: HTMLDivElement = <HTMLDivElement>(document.getElementById(divId));
            let diagram: go.Diagram = go.Diagram.fromDiv(div);
            if (diagram) {
                diagram.model = go.Model.fromJson(JSON.stringify(model));
            } else {
                throw Error("No Diagram on page is associated with a div with id " + divId);
            }
        }
    }

    /**
     * Save the current diagram's model data to cloud storage with the {@link ui} for this class. 
     * @return {Promise} Returns a Promise that resolves with a {@link DiagramFile} representing the saved file.
    */
    public saveWithUI() {
        return new Promise(function(resolve: Function, reject: Function){
            reject("saveWithUI not implemented");
        }); 
    }

    /**
     * Save {@link managedDiagrams}' model data to storage. If path is supplied save to that path. If no path is supplied but {@link currentDiagramFile} has non-null,
     * valid properties, update saved diagram file content at the path in storage corresponding to currentDiagramFile.path with current managedDiagrams' model data.
     * <p>Rules for valid filepaths by subclass: </p>
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {Promise} Returns a Promise that resolves with a  {@link DiagramFile} representing the saved file
    */
    public save(path?: string) {
        return new Promise(function(resolve: Function, reject: Function){
            reject("save not implemented");
        }); 
    }

    /**
     * Load diagram model data from a given cloud storage-specific file path into {@link managedDiagrams}. 
     * @param {string} path A valid filepath. What is meant by this varies from subclass to subclass. Rules for valid filepaths by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {Promise} Returns a Promise that resolves with a {@link DiagramFile}
    */
    public load(path: string) {
        return new Promise(function(resolve: Function, reject: Function){
            reject("load not implemented");
        }); 
    }

    /**
     * Load diagram model data from cloud storage into {@link managedDiagrams} using the {@link ui} for this class. 
     * @return {Promise} Returns a Promise that resolves with a {@link DiagramFile} representing the loaded file
    */
    public loadWithUI() {
        return new Promise(function(resolve: Function, reject: Function){
            reject("loadWithUI not implemented");
        }); 
    }

    /**
     * Remove a file containing diagram model data at a given cloud storage-specific file path. 
     * @param {string} path A valid filepath. What is meant by this varies from subclass to subclass. Rules for valid filepaths by subclass: 
     * <ul>
     *  <li>{@link GoLocalStorage}: Just the filename (the key in local storage); i.e. <code>example.diagram</code></li>
     *  <li>{@link GoDropBox}: <code>/{path-to-file}/{filename}</code>; i.e. <code>/Public/example.diagram</code></li>
     *  <li>{@link GoGoogleDrive}: Use Google Drive-given file IDs. Parameter is still called 'path' in GoGoogleDrive methods to preserve system nomenclature.</li>
     *  <li>{@link GoOneDrive}: <code>/drive/root:/{path-to-file}/{filename}</code>; i.e. <code>/drive/root:/Documents/example.diagram</code></li>
     * </ul>
     * @return {Promise} Returns a Promise that resolves with a {@link DiagramFile} representing the deleted file.
    */
    public remove(path: string) {
        return new Promise(function(resolve: Function, reject: Function){
            reject("remove not implemented");
        }); 
    }

    /**
     * Remove a given diagram from cloud storage using the {@link ui} for this class. 
     * @return {Promise} Returns a Promise that resolves with a {@link DiagramFile} representing the deleted file
    */
    public removeWithUI() {
        return new Promise(function(resolve: Function, reject: Function){
            reject("removeWithUI not implemented");
        }); 
    }

}





