// 
// Copyright (c) Microsoft and contributors.  All rights reserved.
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// 
// See the License for the specific language governing permissions and
// limitations under the License.
// 

// Module dependencies.
var _ = require('underscore');

var azureCommon = require('./../../../common/common.core');
var azureutil = azureCommon.util;
var Constants = azureCommon.Constants;
var HeaderConstants = Constants.HeaderConstants;

/**
* Creates a new BlobResult object.
* @class
* The BlobResult class is used to store the blob information.
* 
 * @property  {string}                      container                             The container name.
 * @property  {string}                      name                                  The blob name.
 * @property  {object}                      metadata                              The metadata key/value pair.
 * @property  {string}                      etag                                  The etag.
 * @property  {string}                      lastModified                          The date/time that the blob was last modified.
 * @property  {string}                      contentLength                         The size of the blob in bytes.
 * @property  {string}                      blobType                              The blob type.
 * @property  {boolean}                     isIncrementalCopy                     If the blob is incremental copy blob.
 * @property  {string}                      requestId                             The request id.
 * @property  {string}                      sequenceNumber                        The current sequence number for a page blob.
 * @property  {string}                      contentRange                          The content range.
 * @property  {string}                      committedBlockCount                   The committed block count.
 * @property  {string}                      serverEncrypted                       If the blob data and application metadata are completely encrypted using the specified algorithm. true/false.
 * @property  {object}                      contentSettings                       The content settings.
 * @property  {string}                      contentSettings.contentType           The content type.
 * @property  {string}                      contentSettings.contentEncoding       The content encoding.
 * @property  {string}                      contentSettings.contentLanguage       The content language.
 * @property  {string}                      contentSettings.cacheControl          The cache control.
 * @property  {string}                      contentSettings.contentDisposition    The content disposition.
 * @property  {string}                      contentSettings.contentMD5            The content MD5 hash.
 * @property  {object}                      lease                                 The lease information.
 * @property  {string}                      lease.id                              The lease id.
 * @property  {string}                      lease.status                          The lease status.
 * @property  {string}                      lease.state                           The lease state.
 * @property  {string}                      lease.duration                        The lease duration.
 * @property  {object}                      copy                                  The copy information.
 * @property  {string}                      copy.id                               The copy id.
 * @property  {string}                      copy.status                           The copy status.
 * @property  {string}                      copy.completionTime                   The copy completion time. 
 * @property  {string}                      copy.statusDescription                The copy status description.
 * @property  {string}                      copy.destinationSnapshot              The snapshot time of the last successful incremental copy snapshot for this blob.
 * @property  {string}                      copy.progress                         The copy progress.
 * @property  {string}                      copy.source                           The copy source.
 * 
* @constructor
* @param {string} [container]  The container name.
* @param {string} [name]       The blob name.
*/
function BlobResult(container, name) {
  if (container) {
    this.container = container;
  }

  if (name) {
    this.name = name;
  }
}

BlobResult.parse = function (blobXml) {
  var blobResult = new BlobResult();
  
  for (var propertyName in blobXml) {
    if (blobXml.hasOwnProperty(propertyName)) {
      if (propertyName === 'Properties') {
        //  Lift out the properties onto the main object to keep consistent across all APIs like: getBlobProperties
        azureutil.setPropertyValueFromXML(blobResult, blobXml[propertyName], true);
      } else if (propertyName === 'Metadata') {
        var resultPropertyName = azureutil.normalizePropertyNameFromXML(propertyName);
        blobResult[resultPropertyName] = {};
        azureutil.setPropertyValueFromXML(blobResult[resultPropertyName], blobXml[propertyName], false);
      } else {
        blobResult[propertyName.toLowerCase()] = blobXml[propertyName];
      }
    }
  }

  if (blobResult.isIncrementalCopy !== undefined) {
    blobResult.isIncrementalCopy = (blobResult.isIncrementalCopy === 'true');
  }

  // convert accessTierInferred to boolean type
  if (blobResult.accessTierInferred !== undefined) {
    blobResult.accessTierInferred = (blobResult.accessTierInferred === 'true');
  }

  if (blobResult.deleted !== undefined) {
    blobResult.deleted = (blobResult.deleted == 'true');
  }

  if (blobResult.remainingRetentionDays !== undefined) {
    blobResult.remainingRetentionDays = parseInt(blobResult.remainingRetentionDays);
  }

  return blobResult;
};

var headersForProperties = {
  'lastModified': 'LAST_MODIFIED',
  'creationTime': 'CREATION_TIME',
  'etag': 'ETAG',
  'sequenceNumber': 'SEQUENCE_NUMBER',
  'blobType': 'BLOB_TYPE',
  'contentLength': 'CONTENT_LENGTH',
  'blobContentLength': 'BLOB_CONTENT_LENGTH',
  'contentRange': 'CONTENT_RANGE',
  'committedBlockCount': 'BLOB_COMMITTED_BLOCK_COUNT',
  'serverEncrypted': 'SERVER_ENCRYPTED',
  'requestId': 'REQUEST_ID',
  
  'range': 'RANGE',
  'blobRange': 'STORAGE_RANGE',
  'getContentMd5': 'RANGE_GET_CONTENT_MD5',
  'acceptRanges': 'ACCEPT_RANGES',
  'appendOffset': 'BLOB_APPEND_OFFSET',

  'accessTier': 'ACCESS_TIER',
  'accessTierChangeTime': 'ACCESS_TIER_CHANGE_TIME',  
  'accessTierInferred': 'ACCESS_TIER_INFERRED',
  'archiveStatus': 'ARCHIVE_STATUS',

  'isIncrementalCopy': 'INCREMENTAL_COPY',
  
  // ContentSettings
  'contentSettings.contentType': 'CONTENT_TYPE',
  'contentSettings.contentEncoding': 'CONTENT_ENCODING',
  'contentSettings.contentLanguage': 'CONTENT_LANGUAGE',
  'contentSettings.cacheControl': 'CACHE_CONTROL',
  'contentSettings.contentDisposition': 'CONTENT_DISPOSITION',
  'contentSettings.contentMD5': 'CONTENT_MD5',

  // Lease
  'lease.id': 'LEASE_ID',
  'lease.status': 'LEASE_STATUS',
  'lease.duration': 'LEASE_DURATION',
  'lease.state': 'LEASE_STATE',

  // Copy
  'copy.id': 'COPY_ID',
  'copy.status': 'COPY_STATUS',
  'copy.source': 'COPY_SOURCE',
  'copy.progress': 'COPY_PROGRESS',
  'copy.completionTime': 'COPY_COMPLETION_TIME',
  'copy.statusDescription': 'COPY_STATUS_DESCRIPTION',
  'copy.destinationSnapshot': 'COPY_DESTINATION_SNAPSHOT'
};

BlobResult.prototype.getPropertiesFromHeaders = function (headers) {
  var self = this;

  var setBlobPropertyFromHeaders = function (blobProperty, headerProperty) {
    if (!azureutil.tryGetValueChain(self, blobProperty.split('.'), null) && headers[headerProperty.toLowerCase()]) {
      azureutil.setObjectInnerPropertyValue(self, blobProperty.split('.'), headers[headerProperty.toLowerCase()]);
      
      if (blobProperty === 'copy.progress') {
        var info = azureutil.parseCopyProgress(self.copy.progress);
        self.copy.bytesCopied = parseInt(info.bytesCopied);
        self.copy.totalBytes = parseInt(info.totalBytes);
      }
    }
  };

  // For range get, 'x-ms-blob-content-md5' indicate the overall MD5 of the blob. Try to set the contentMD5 using this header if it presents
  setBlobPropertyFromHeaders('contentSettings.contentMD5', HeaderConstants.BLOB_CONTENT_MD5);
  
  _.chain(headersForProperties).pairs().each(function (pair) {
    var property = pair[0];
    var header = HeaderConstants[pair[1]];
    setBlobPropertyFromHeaders(property, header);
  });

  // convert isIncrementalCopy to boolean type
  if (self.isIncrementalCopy !== undefined) {
    self.isIncrementalCopy = (self.isIncrementalCopy === 'true');
  }

  // convert accessTierInferred to boolean type  
  if (self.accessTierInferred !== undefined) {
    self.accessTierInferred = (self.accessTierInferred == 'true');
  }
};

/**
* This method sets the HTTP headers and is used by all methods except setBlobProperties and commitBlocks. Those 2 methods will set the x-ms-* headers using setPropertiesFromBlob.
* @ignore
*/
BlobResult.setHeadersFromBlob = function (webResource, blob) {
  var setHeaderPropertyFromBlob = function (headerProperty, blobProperty) {
    var blobPropertyValue = azureutil.tryGetValueChain(blob, blobProperty.split('.'), null);
    if (blobPropertyValue) {
      webResource.withHeader(headerProperty, blobPropertyValue);
    }
  };

  if (blob) {
    // Content-Type
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_TYPE, 'contentSettings.contentType');

    // Content-Encoding
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_ENCODING, 'contentSettings.contentEncoding');

    // Content-Language
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_LANGUAGE, 'contentSettings.contentLanguage');

    // Content-Disposition
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_DISPOSITION, 'contentSettings.contentDisposition');

    // Cache-Control
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CACHE_CONTROL, 'contentSettings.cacheControl');

    // Blob's Content-MD5
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_MD5, 'contentSettings.contentMD5');

    // Content-Length
    setHeaderPropertyFromBlob(HeaderConstants.CONTENT_LENGTH, 'contentLength');

    // transactional Content-MD5
    setHeaderPropertyFromBlob(HeaderConstants.CONTENT_MD5, 'transactionalContentMD5');

    // Range
    if (!azureutil.objectIsNull(blob.rangeStart)) {
      var range = 'bytes=' + blob.rangeStart + '-';

      if (!azureutil.objectIsNull(blob.rangeEnd)) {
        range += blob.rangeEnd;
      }

      webResource.withHeader(HeaderConstants.RANGE, range);
    }

    // Source Range
    if (!azureutil.objectIsNull(blob.sourceRangeStart)) {
      var sourceRange = 'bytes=' + blob.sourceRangeStart + '-';

      if (!azureutil.objectIsNull(blob.sourceRangeEnd)) {
        sourceRange += blob.sourceRangeEnd;
      }

      webResource.withHeader(HeaderConstants.SOURCE_RANGE, sourceRange);
    }

    // Blob Type
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_TYPE, 'blobType');

    // Lease id
    setHeaderPropertyFromBlob(HeaderConstants.LEASE_ID, 'leaseId');

    // Sequence number
    setHeaderPropertyFromBlob(HeaderConstants.SEQUENCE_NUMBER, 'sequenceNumber');
    setHeaderPropertyFromBlob(HeaderConstants.SEQUENCE_NUMBER_ACTION, 'sequenceNumberAction');

    if (blob.metadata) {
      webResource.addOptionalMetadataHeaders(blob.metadata);
    }
  }
};

/**
* This method sets the x-ms-* headers and is used by setBlobProperties and commitBlocks. All other methods will set the regular HTTP headers using setHeadersFromBlob.
* @ignore
*/
BlobResult.setPropertiesFromBlob = function (webResource, blob) {
  var setHeaderPropertyFromBlob = function (headerProperty, blobProperty) {
    var propertyValue = azureutil.tryGetValueChain(blob, blobProperty.split('.'), null);
    if (propertyValue) {
      webResource.withHeader(headerProperty, propertyValue);
    }
  };

  if (blob) {
    // Content-Type
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_TYPE, 'contentSettings.contentType');

    // Content-Encoding
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_ENCODING, 'contentSettings.contentEncoding');

    // Content-Language
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_LANGUAGE, 'contentSettings.contentLanguage');

    // Content-Disposition
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_DISPOSITION, 'contentSettings.contentDisposition');

    // Cache-Control
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CACHE_CONTROL, 'contentSettings.cacheControl');

    // Content-MD5
    setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_MD5, 'contentSettings.contentMD5');

    // Lease id
    setHeaderPropertyFromBlob(HeaderConstants.LEASE_ID, 'leaseId');

    if (blob.metadata) {
      webResource.addOptionalMetadataHeaders(blob.metadata);
    }
  }
};

module.exports = BlobResult;
