/* 
 * Copyright 2011 Robert Theis
 * Copyright 2015 Jakub Kříž
 *
 * 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.
 */

package cz.muni.fi.digitrecognition;


import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;

/**
 * Class to send OCR requests to the OCR engine in a separate thread, send a success/failure message,
 * and dismiss the indeterminate progress dialog box.
 */
final class OcrRecognizeAsyncTask extends AsyncTask<Void, Void, Boolean> {

  private CaptureActivity activity;
  private byte[] data;
  private int width;
  private int height;
  private OcrResult ocrResult;
  private long timeRequired;
  private static float consumedData;

  private static String scriptPath;

  private int statusCode;
  


  OcrRecognizeAsyncTask(CaptureActivity activity, byte[] data, int width, int height) {
    this.activity = activity;
    this.data = data;
    this.width = width;
    this.height = height;
    consumedData = 0f;
    statusCode = 0;

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    scriptPath = prefs.getString(PreferencesActivity.KEY_SCRIPT_PATH, "http://www.fi.muni.cz/~xkriz9/recognition.cgi");

  }

  @Override
  protected Boolean doInBackground(Void... arg0) {
    long start = System.currentTimeMillis();
    Bitmap bitmap = activity.getCameraManager().buildLuminanceSource(data, width, height).renderCroppedGreyscaleBitmap();
    String textResult = null;

    try {
    	//resize the bitmap to sent the smaller amount of data
    	Bitmap tmp = Bitmap.createScaledBitmap(bitmap, 640, bitmap.getHeight(), false);
    	//convert bitmap to byte array
    	ByteArrayOutputStream stream = new ByteArrayOutputStream();
    	tmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    	bitmap = tmp;
    	
    	byte[] rslt = stream.toByteArray();

    	textResult = postFile(rslt);

    	timeRequired = System.currentTimeMillis() - start;
//        Log.e("OcrTimeRequired", "total time=" + timeRequired);

      // Check for failure to recognize text
	  if (textResult == null || textResult.equals("")) {
	    return false;
	  }
	  ocrResult = new OcrResult();
	} catch (RuntimeException e) {
	  Log.e("OcrRecognizeAsyncTask", "Caught RuntimeException in request to OCRHMM. Setting state to CONTINUOUS_STOPPED.");
	  e.printStackTrace();
	  try {
	    activity.stopHandler();
	  } catch (NullPointerException e1) {
	    // Continue
	  }
	  return false;
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	//timeRequired = System.currentTimeMillis() - start;
	ocrResult.setBitmap(bitmap);
	ocrResult.setText(textResult);
	ocrResult.setRecognitionTimeRequired(timeRequired);
    ocrResult.setConsumedData(consumedData);
	return true;
  }

  @Override
  protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);

    //Server error
    if(statusCode >= 500) {
      Toast toast = Toast.makeText(activity, "Server error.", Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.TOP, 0, 0);
      toast.show();
    //Not found
    } else if(statusCode == 404) {
      Toast toast = Toast.makeText(activity, "Wrong script path.", Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.TOP, 0, 0);
      toast.show();
      //Client error
    } else if(statusCode >= 400 ) {
      Toast toast = Toast.makeText(activity, "Client error.", Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.TOP, 0, 0);
      toast.show();
    }

    Handler handler = activity.getHandler();
    if (handler != null) {
      // Send results for single-shot mode recognition.
      if (result) {
        Message message = Message.obtain(handler, R.id.ocr_decode_succeeded, ocrResult);
        message.sendToTarget();
      } else {
        Message message = Message.obtain(handler, R.id.ocr_decode_failed, ocrResult);
        message.sendToTarget();
      }
      activity.getProgressDialog().dismiss();
    }
  }

  private String postFile(byte[] data) throws Exception {
        HttpClient client = new DefaultHttpClient();
	    String url = scriptPath;
        try {
          HttpPost post = new HttpPost(url);

          MultipartEntityBuilder builder = MultipartEntityBuilder.create();
          builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

          builder.addBinaryBody("image", data);

          HttpEntity entity = builder.build();
          post.setEntity(entity);
          consumedData += post.getEntity().getContentLength();
          HttpResponse response = client.execute(post);
          consumedData += response.getEntity().getContentLength();

          //Status OK
          if(response.getStatusLine().getStatusCode() == 200)
              return getContent(response);

          statusCode = response.getStatusLine().getStatusCode();
        } catch (ClientProtocolException e) {
            Log.e("ClientProtocolException : "+e, e.getMessage());
        } catch (IOException e) {
            Log.e("IOException : "+e, e.getMessage());
        } catch(IllegalArgumentException e) {
            Log.e("OcrRecognizeAsyncTask", "Wrong path to script." + e.getMessage());
        }

        return "";
	} 

	public static String getContent(HttpResponse response) throws IOException {
	    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
	    String body = "";
	    String content = "";

	    while ((body = rd.readLine()) != null)  {
	        content += body + "\n";
	    }
	    return content.trim();
	}
  
}
