package org.reactnative.camera.tasks;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Result> {
  private byte[] mImageData;
  private int mWidth;
  private int mHeight;
  private BarCodeScannerAsyncTaskDelegate mDelegate;
  private final MultiFormatReader mMultiFormatReader;

  //  note(sjchmiela): From my short research it's ok to ignore rotation of the image.
  public BarCodeScannerAsyncTask(
      BarCodeScannerAsyncTaskDelegate delegate,
      MultiFormatReader multiFormatReader,
      byte[] imageData,
      int width,
      int height
  ) {
    mImageData = imageData;
    mWidth = width;
    mHeight = height;
    mDelegate = delegate;
    mMultiFormatReader = multiFormatReader;
  }

  @Override
  protected Result doInBackground(Void... ignored) {
    if (isCancelled() || mDelegate == null) {
      return null;
    }

    Result result = null;

    try {
      BinaryBitmap bitmap = generateBitmapFromImageData(mImageData, mWidth, mHeight);
      result = mMultiFormatReader.decodeWithState(bitmap);
    } catch (NotFoundException e) {
      BinaryBitmap bitmap = generateBitmapFromImageData(rotateImage(mImageData,mWidth, mHeight), mHeight, mWidth);
      try {
        result = mMultiFormatReader.decodeWithState(bitmap);
      } catch (NotFoundException e1) {
        //no barcode Found
      }
    } catch (Throwable t) {
      t.printStackTrace();
    }

    return result;
  }
  private byte[] rotateImage(byte[]imageData,int width, int height) {
    byte[] rotated = new byte[imageData.length];
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        rotated[x * height + height - y - 1] = imageData[x + y * width];
      }
    }
    return rotated;
  }
  @Override
  protected void onPostExecute(Result result) {
    super.onPostExecute(result);
    if (result != null) {
      mDelegate.onBarCodeRead(result, mWidth, mHeight);
    }
    mDelegate.onBarCodeScanningTaskCompleted();
  }

  private BinaryBitmap generateBitmapFromImageData(byte[] imageData, int width, int height) {
    PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
        imageData, // byte[] yuvData
        width, // int dataWidth
        height, // int dataHeight
        0, // int left
        0, // int top
        width, // int width
        height, // int height
        false // boolean reverseHorizontal
    );
    return new BinaryBitmap(new HybridBinarizer(source));
  }
}

@@ -1212,35 +1212,106 @@
 ata(
-mImageData, mWidth, mHeight
+%0A              mImageData,%0A              mWidth,%0A              mHeight,%0A              false%0A      
 );%0A 
@@ -1460,16 +1460,31 @@
 ageData(
+%0A              
 rotateIm
@@ -1519,24 +1519,80 @@
 ht),
- mHeight, mWidth
+%0A              mHeight,%0A              mWidth,%0A              false%0A      
 );%0A 
@@ -1714,26 +1714,729 @@
     
-//no barcode Found
+  BinaryBitmap invertedBitmap = generateBitmapFromImageData(%0A                  mImageData,%0A                  mWidth,%0A                  mHeight,%0A                  true%0A          );%0A        try %7B%0A          result = mMultiFormatReader.decodeWithState(invertedBitmap);%0A        %7D catch (NotFoundException e2) %7B%0A          BinaryBitmap invertedRotatedBitmap = generateBitmapFromImageData(%0A                  rotateImage(mImageData,mWidth, mHeight),%0A                  mHeight,%0A                  mWidth,%0A                  true%0A          );%0A          try %7B%0A            result = mMultiFormatReader.decodeWithState(invertedRotatedBitmap);%0A          %7D catch (NotFoundException e3) %7B%0A            //no barcode Found%0A          %7D%0A        %7D
 %0A   
@@ -3150,32 +3150,49 @@
 idth, int height
+, boolean inverse
 ) %7B%0A    PlanarYU
@@ -3499,24 +3499,127 @@
 ntal%0A    );%0A
+    if (inverse) %7B%0A      return new BinaryBitmap(new HybridBinarizer(source.invert()));%0A    %7D else %7B%0A  
     return n
@@ -3664,14 +3664,20 @@
 urce));%0A
+    %7D%0A
   %7D%0A%7D%0A

support inverted qrcode (#2135)