define(function(require, exports, module) {
'use strict';

/**
 * Dependencies
 */

var debug = require('debug')('controller:storage');
var bindAll = require('lib/bind-all');
var Storage = require('lib/storage');

/**
 * Exports
 */

module.exports = function(app) { return new StorageController(app); };
module.exports.StorageController = StorageController;

/**
 * Initialize a new `StorageController`
 *
 * @param {App} app
 */
function StorageController(app) {
  bindAll(this);
  this.app = app;
  this.camera = app.camera;
  this.settings = app.settings;
  this.storage = app.storage || new Storage();
  this.bindEvents();
  this.configure();
  debug('initialized');
}

/**
 * Initial configuration.
 *
 * Give the camera a way to create video filepaths.
 * This is so that the camera can record videos
 * directly to the final location without us
 * having to move the video file from temporary,
 * to final location at recording end.
 *
 * @private
 */
StorageController.prototype.configure = function() {
  this.storage.configure();
  this.camera.createVideoFilepath = this.storage.createVideoFilepath;
  this.updateMaxFileSize();
};

/**
 * Bind to relevant events.
 *
 * @private
 */
StorageController.prototype.bindEvents = function() {
  debug('bind events');

  // App
  this.settings.pictureSizes.on('change:selected', this.updateMaxFileSize);
  this.app.on('previewgallery:deletepicture', this.storage.deletePicture);
  this.app.on('previewgallery:deletevideo', this.storage.deleteVideo);
  this.app.on('settings:configured', this.updateMaxFileSize);
  this.app.on('camera:newimage', this.storePicture);
  this.app.on('camera:newvideo', this.storeVideo);
  this.app.on('visible', this.storage.check);

  // Storage
  this.storage.on('volumechanged', this.app.firer('storage:volumechanged'));
  this.storage.on('itemdeleted', this.app.firer('storage:itemdeleted'));
  this.storage.on('changed', this.onChanged);
  this.storage.on('checked', this.onChecked);
  debug('events bound');
};

/**
 * Relay storage state change events.
 *
 * @param  {String} state
 * @private
 */
StorageController.prototype.onChanged = function(state) {
  debug('changed: %s', state);
  this.app.emit('storage:changed', state);
};

/**
 * Emit the outcome of a storage check
 * so that other parts of the app
 * can respond.
 *
 * @param  {String} value
 * @private
 */
StorageController.prototype.onChecked = function(value) {
  debug('checked: %s', value);
  this.app.emit('storage:checked', value);
  this.app.emit('storage:checked:' + value);
};

/**
 * Store a picture.
 *
 * In either case, save the memory-backed
 * photo blob to device storage, retrieve
 * the resulting File (blob) and pass that
 * around instead of the original memory blob.
 *
 * This is critical for "pick" activity consumers
 * where the memory-backed Blob is either highly
 * inefficent or will almost-immediately become
 * inaccesible, depending on the state of the
 * platform. https://bugzil.la/982779
 *
 * @param  {Object} picture
 * @private
 */
StorageController.prototype.storePicture = function(picture) {
  var memoryBlob = picture.blob;
  var self = this;

  this.storage.addPicture(
    memoryBlob,
    function(error, filepath, abspath, fileBlob) {
      picture.blob = fileBlob;
      picture.filepath = filepath;
      debug('stored picture', picture);
      self.app.emit('newmedia', picture);
  });
};

/**
 * Store a video.
 *
 * We don't store the video blob like
 * we do for images, as it is recorded
 * directly to the final location.
 * This is for memory reason. The poster
 * is also automatically created.
 *
 * @param  {Object} video
 */
StorageController.prototype.storeVideo = function(video) {
  debug('new video', video);
  var poster = video.poster;
  var self = this;

  // Add the poster image to the image storage
  poster.filepath = video.filepath.replace('.3gp', '.jpg');
  video.isVideo = true;

  this.storage.addPicture(
    poster.blob,
    { filepath: poster.filepath },
    function(error, path, absolutePath, fileBlob) {
      // Replace the memory-backed Blob with the DeviceStorage file-backed File.
      // Note that "video" has a reference to "poster", so video previews will
      // use this File.
      poster.blob = fileBlob;
      debug('new video', video);
      self.app.emit('newmedia', video);
  });
};

/**
 * Calculate and set a `maxFileSize`
 * value on the storage instance.
 *
 * This is so that it can alert us when there
 * isn't enough space left in storage
 * to accomodate a new picture.
 *
 * It is very unlikely that a JPEG file will have a file size that is
 * more than half a byte per pixel. There is some fixed EXIF overhead
 * that is the same for small and large pictures, however, so we add
 * an additional 25,000 bytes of padding.
 *
 * @private
 */
StorageController.prototype.updateMaxFileSize = function() {
  var pictureSize = this.settings.pictureSizes.selected('data');
  /* Depending on when we get loaded, we may not have a picture size yet. */
  if (pictureSize) {
    var bytes = (pictureSize.width * pictureSize.height / 2) + 25000;
    this.storage.setMaxFileSize(bytes);
    debug('maxFileSize updated %s', bytes);
  }
};

});
