/*globals qq */
qq.Identify = function(fileOrBlob, log) {
    "use strict";

    function isIdentifiable(magicBytes, questionableBytes) {
        var identifiable = false,
            magicBytesEntries = [].concat(magicBytes);

        qq.each(magicBytesEntries, function(idx, magicBytesArrayEntry) {
            if (questionableBytes.indexOf(magicBytesArrayEntry) === 0) {
                identifiable = true;
                return false;
            }
        });

        return identifiable;
    }

    qq.extend(this, {
        /**
         * Determines if a Blob can be displayed natively in the current browser.  This is done by reading magic
         * bytes in the beginning of the file, so this is an asynchronous operation.
         *
         * @returns {qq.Promise} Promise that is fulfilled when identification is complete.
         * If successful, the MIME string is passed to the success handler.
         */
        isPreviewable: function() {
            var self = this,
                idenitifer = new qq.Promise(),
                previewable = false,
                name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name;

            log(qq.format("Attempting to determine if {} can be rendered in this browser", name));

            qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) {
                qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) {
                    if (isIdentifiable(bytes, hex)) {
                        // Safari is the only supported browser that can deal with TIFFs natively,
                        // so, if this is a TIFF and the UA isn't Safari, declare this file "non-previewable".
                        if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) {
                            previewable = true;
                            idenitifer.success(mime);
                        }

                        return false;
                    }
                });

                log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT"));

                if (!previewable) {
                    idenitifer.failure();
                }
            },
            function() {
                log("Error reading file w/ name '" + fileOrBlob.name + "'.  Not able to be rendered in this browser.");
                idenitifer.failure();
            });

            return idenitifer;
        },

        /**
         * Determines if a Blob can be displayed natively in the current browser.  This is done by checking the
         * blob's type attribute.  This is a synchronous operation, useful for situations where an asynchronous operation
         * would be challenging to support.  Note that the blob's type property is not as accurate as reading the
         * file's magic bytes.
         *
         * @returns {Boolean} true if the blob can be rendered in the current browser
         */
        isPreviewableSync: function() {
            var fileMime = fileOrBlob.type,
                // Assumption: This will only ever be executed in browsers that support `Object.keys`.
                isRecognizedImage = qq.indexOf(Object.keys(this.PREVIEWABLE_MIME_TYPES), fileMime) >= 0;

            if (isRecognizedImage) {
                if (fileMime === "image/tiff") {
                    return qq.supportedFeatures.tiffPreviews;
                }
                return true;
            }
            return false;
        }
    });
};

qq.Identify.prototype.PREVIEWABLE_MIME_TYPES = {
    "image/jpeg": "ffd8ff",
    "image/gif": "474946",
    "image/png": "89504e",
    "image/bmp": "424d",
    "image/tiff": ["49492a00", "4d4d002a"]
};

@@ -728,16 +728,126 @@
 eration.
+  Before we attempt to read the%0A         * file, we will examine the blob's type attribute to save CPU cycles.
 %0A       
@@ -1357,24 +1357,218 @@
 %22, name));%0A%0A
+            log(%22First pass: check type attribute of blob object.%22);%0A%0A            if (this.isPreviewableSync()) %7B%0A                log(%22Second pass: check for magic bytes in file header.%22);%0A%0A    
             
@@ -1619,24 +1619,28 @@
 tion(hex) %7B%0A
+    
             
@@ -1720,24 +1720,28 @@
             
+ 
+   
 if (isIdenti
@@ -1786,16 +1786,20 @@
         
+  
+  
 // Safar
@@ -1865,16 +1865,20 @@
 tively,%0A
+    
         
@@ -2000,24 +2000,28 @@
             
+    
 if (mime !==
@@ -2094,32 +2094,36 @@
                 
+ 
+   
 previewable = tr
@@ -2118,32 +2118,36 @@
 iewable = true;%0A
+    
                 
@@ -2184,16 +2184,20 @@
 (mime);%0A
+    
         
@@ -2231,32 +2231,36 @@
                 
+    
 return false;%0A  
@@ -2249,32 +2249,36 @@
   return false;%0A
+    
                 
@@ -2291,37 +2291,45 @@
                 
+    
 %7D);%0A%0A
+    
                 
@@ -2439,24 +2439,28 @@
             
+    
 if (!preview
@@ -2479,32 +2479,36 @@
                 
+   
+ 
 idenitifer.failu
@@ -2521,34 +2521,42 @@
                 
-%7D%0A
+    %7D%0A    
             %7D,%0A 
@@ -2562,24 +2562,28 @@
             
+    
 function() %7B
@@ -2575,32 +2575,36 @@
    function() %7B%0A
+    
                 
@@ -2707,16 +2707,111 @@
 ser.%22);%0A
+                    idenitifer.failure();%0A                %7D);%0A            %7D%0A            else %7B%0A
         
@@ -2845,34 +2845,32 @@
 );%0A            %7D
-);
 %0A%0A            re
@@ -3688,16 +3688,53 @@
 me) %3E= 0
+,%0A                previewable = false
 ;%0A%0A     
@@ -3834,22 +3834,29 @@
         
+p
 re
-turn
+viewable =
  qq.supp
@@ -3921,21 +3921,59 @@
     
-return
+else %7B%0A                    previewable =
  true;%0A
+    
     
@@ -3990,35 +3990,172 @@
             
-return fals
+%7D%0A%0A            !previewable && log(fileOrBlob.name + %22 is not previewable in this browser per the blob's type attr%22);%0A%0A            return previewabl
 e;%0A        %7D

check blob's type attr before reading it #1139