(function() {
 
 
/**
 * The File class is used to represent a file in the file system. It's little more
 * than a property bag, but with documentation. Typically you don't instantiate these
 * yourself, but use an Ext.space.files.Collection object to create them.
 */
Ext.define("Ext.space.files.File", {
 
    /***
    * @private
    * @readonly
    * The default protocol for the URL of the file, if one is not provided by the native client.
    */
    urlProtocol: "sfile://",
 
    /**
     * File system key
     * @readonly
     * @type {Number}
     */
    key: null,
 
 
    /**
     * The local URL in the secure file system.
     * This URL can be referenced inside of application as part of an image or an
     * in-line style or any where the browser makes a network request for a resource.
     *
     * This URL can only be accessed by this application, cross application requests
     * are not allowed.
     *
     * The value of this string should be considered temporary and could change from
     * release to release Do not store the value other than in memory.
     *
     * @readonly
     * @type {String}
     */
    url: null,
 
 
    /**
     * Filename (excluding path)
     * @readonly
     * @type {String}
     */
    name: null,
 
    /**
     * Creation timestamp
     * @readonly
     * @type {Date}
     */
    created: null,
 
    /**
     * Last Modified timestamp
     * @readonly
     * @type {Date}
     */
    modified: null,
 
    /**
     * MIME type
     * @readonly
     * @type {String}
     */
    mimeType: null,
 
    /**
     * Simplified file type
     * @readonly
     * @type {String}
     */
    type: null,
 
    /**
     * Name of the application that created/owns this file
     * @readonly
     * @type {String}
     */
    appName: null,
 
    /**
     * ID of the application that created/owns this file
     * @readonly
     * @type {String}
     */
    appId: null,
 
    /**
     * Virtual path to the file
     * @readonly
     * @type {String}
     */
    path: null,
 
    /**
     * File size in bytes
     * @readonly
     * @type {Number}
     */
    size: 0,
 
    /**
     * Collection which owns this file
     * @private
     * @type {Ext.space.files.Collection}
     */
    collection: null,
 
    /**
    * @private
    */
    constructor: function(args) {
        this._updateWith(args);
    },
 
    /**
     * Bulk update this file object with the data provided.
     *
     * @private
     * @param {Object} source Object with data to overwrite onto this File
     */
    _updateWith: function(source) {
        if (source) {
            if (source.name) { this.name = source.name; }
            if (source.key) {
                this.key = source.key;
                this.url = source.url || (this.urlProtocol + source.key);
            }
 
            // convert dates from epoch seconds 
            if (source.created) { this.created = new Date(source.created * 1000); }
            if (source.modified) { this.modified = new Date(source.modified * 1000); }
 
            if (source.type) {
                this.mimeType = source.type;
 
                this.type = source.type.substring(source.type.indexOf("/")+1);
             }
            if (source.appName) { this.appName = source.appName; }
            if (source.appId) { this.appId = source.appId; }
            if (source.hasOwnProperty("size")) { this.size = source.size; }
        }
        return this;
    },
 
    /**
     * Alias of Ext.space.files.Collection#get
     *
     * Fetch the contents of the file.
     *
     *      file.getContents().then(function(contents) {
     *          // do something with the contents
     *      });
     *
     * @return {Ext.space.Promise} Promise that resolves when the contents are fetched
     *
     * @inheritdoc Ext.space.files.Collection#get
     */
    getContents: function() {
        return this.collection.loadContents(this.key, this);
    },
 
    /**
     * Alias of Ext.space.files.Collection#set
     *
     * Write contents to the file.
     *
     *      file.setContents(contents).then(function() {
     *          // success
     *      });
     *
     * @param {String} contents File contents to write
     * @return {Ext.space.Promise} Promise that resolves when the contents are fetched
     *
     * @inheritdoc Ext.space.files.Collection#set
     */
    setContents: function(contents) {
        return this.collection.writeContents(this.key, contents);
    },
 
    /**
     * Alias of Ext.space.files.Collection#remove
     *
     * Remove this file from disk.
     *
     *      file.remove().then(function(success) {
     *          // success?
     *      });
     *
     * @return {Ext.space.Promise} Promise that resolves when the file is removed
     *
     * @inheritdoc Ext.space.files.Collection#remove
     */
    remove: function() {
        return this.collection.removeFile(this.key);
    },
 
    /**
     * Alias of Ext.space.files.Collection#view
     *
     * Open the native viewer for this file.
     *
     *      file.view().then(function() {
     *          // launched
     *      });
     *
     * @return {Ext.space.Promise} Promise that resolves when the viewer is launched
     *
     * @inheritdoc Ext.space.files.Collection#view
     */
    view: function() {
        return this.collection.viewFile(this.key);
    },
 
    /**
     * Upload the file to a form handler.
     *
     *      file.upload({
     *          url: "...",
     *          fileFieldName: "...",
     *          params: { // optional extra POST data
     *              param1: "...",
     *              param2: "..."
     *          },
     *          headers: { // optional request headers
     *              header1: "...",
     *              header2: "..."
     *          }
     *      }).then(function(response) {
     *          // inspect the response if you like:
     *          // response.statusCode, .headers, .body
     *      });
     *
     * @param {Object} args Upload parameters
     * @param {String} args.url The URL where the file will be posted.
     * @param {String} args.fileFieldName The post field name to assign the file to.
     * @param {Object} args.params Optional POST parameters to be sent along with the file.
     * @param {Object} args.headers Optional http headers to be sent along with the file.
 
     * @return {Ext.space.Promise} Promise that resolves when the file is uploaded
     */
    upload: function(args) {
        var result = new Ext.space.Promise();
 
        var spec = { key: this.key };
        if (args) {
            spec.url = args.url;
            spec.fileFieldName = args.fileFieldName;
            spec.params = args.params;
            spec.headers = args.headers;
        }
 
        // TODO remove from 1.3; this is only here so the manager code can pass it back 
        spec.file = this;
 
        Ext.space.Uploads.upload(spec).then(function(file, upload) {
            result.fulfill(file, upload);
        }, function(error) {
            result.reject(error);
        });
 
        return result;
    },
 
    /**
     * Compress the file into an archive.
     *
     *      file.compress({ archiveName: "somefiles.zip" }).then(function(archive) {
     *          // do something with the archive file
     *      });
     *
     *      // or specify more options:
     *      file.compress({
     *          archiveName: "somefile.gz",
     *          path: "myArchivePath",
     *          type: "gzip"
     *      }).then(function(archive) {
     *          // do something with the archive file
     *      });
     *
     * @param {Object} args Options object
     * @param {String} args.archiveName Name of the archive file to create
     * @param {String} args.path (optional) Path into which to save the archive; defaults to ""
     * @param {String} args.type (optional) Compression type ("zip", "gzip", "bzip2", "7zip");
     *                           if this is omitted, the system will attempt to determine
     *                           the compression type from the archiveName, and if it
     *                           cannot be determined, defaults to "zip".
     * @return {Ext.space.Promise} Promise that resolves with the Ext.space.files.File
     *                       object for the new archive.
     */
    compress: function(args) {
        var result = new Ext.space.Promise();
 
        if (!args) {
            result.reject("Missing compression arguments");
 
        } else if (!args.archiveName) {
            result.reject("Missing compressed archive name");
 
        } else {
            Ext.space.SecureFiles.compress({
                files: [this],
                archiveName: args.archiveName,
                path: args.path,
                type: args.type
            }).connect(result);
        }
 
        return result;
    },
 
    /**
     * Uncompress into file(s) in a particular path.
     *
     *      file.uncompress("somepath").then(function(files) {
     *          files.forEach(...); // do something with the new file(s)
     *      });
     *
     * @param {String} path (optional) Path into which to place uncompressed
     *                      file(s); defaults to ""
     * @return {Ext.space.Promise} Promise that resolves when the file is uncompressed.
     */
    uncompress: function(path) {
        var uncompressPath = "";
        var result = new Ext.space.Promise();
 
        // prior to version 6, we expected an object parameter with optional .path 
        // and .type properties, so we need to unpack that here if that's what we get 
        // (and we also completely ignore any specified encoding) 
        if (path) {
            uncompressPath = (path.path || path.type) ? (path.path || "") : path;
        }
 
        Ext.space.Communicator.send({
            command: "Compression#uncompress",
            key: this.key,
            path: uncompressPath,
            callbacks: {
                onSuccess: function(metas) {
                    var collection = Ext.space.SecureFiles.get(uncompressPath);
                    var files = [];
 
                    // turn them all into files 
                    metas.forEach(function(meta) {
                        files.push(collection._cache(meta));
                    });
 
                    result.fulfill(files);
                },
                onError: function(error) {
                    result.reject(error);
                }
            }
        });
 
        return result;
    }
});
 
 
})();