package com.fihtdc.UploadAgentService;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.lang.reflect.Method;
import android.os.Bundle;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.util.Log;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.app.Service;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Set;

import com.fihtdc.UploadAgentService.data.FileInfo;
import com.fihtdc.UploadAgentService.database.UploadLogDBHelper;
import com.fihtdc.UploadAgentService.util.Settings;



public class UploadAgent extends Service  {

    protected String TAG = "com.fihtdc.UploadAgentService(" + Settings.VERSION + ")";
    private String mDBLock = "mDBLock";

    /** Command to the Agent to display a message */
    public static final int MSG_AGENT_START = 0; // Bind bind upload service
    public static final int MSG_AGENT_SERVICE_BOUND = 2;// Upload service has bound and send upload file information to service
    public static final int MSG_AGENT_START_WRITE = 1; // get pipe[1] from upload service and create new Thread to write date to pipe[1]
    public static final int MSG_AGENT_COMPLETE_WRITE = 3; // Complete write data
    public static final int MSG_AGENT_SERVICE_OFF = 99;

    /** Command to the service to display a message*/
    public static final int MSG_SERVICE_PREPARE_UPLOAD = 100;
    public static final int MSG_SERVICE_START_READ = 101;
    public static final int MSG_SERVICE_PREPARE_TO_READ = 103;

    /** Parameters of upload file constance*/
    public static final String UPLOAD_FILES = "uploadFiles";
    public static final String UPLOAD_FOLDER = "uploadFolder";
    public static final String UPLOAD_FILE_NAMES = "uploadFileNames";
    public static final String UPLOAD_SIZES = "uploadSizes";
    public static final String UPLOAD_CURRENT_FILE_NAME = "currentUploadFile";
    public static final String UPLOAD_IS_DELETE_AFT_COMPLETE = "deleteAftComplete";
    public static final String UPLOAD_IS_FORCE_UPLOAD = "isForceUpload";
    public static final String UPLOAD_IS_RESEND = "isResend";
    public static final String UPLOAD_SERVICE_NAME = "uploadServiceName";
    protected final String UPLOAD_SERVICE_PACKAGE = "com.fihtdc.AprUploadService";
    protected final String UPLOAD_SERVICE ="com.fihtdc.AprUploadService.service.UploadService";
    protected String UPLOAD_AGENT_PACKAGE = "uploadAgentPackage";
    protected String UPLOAD_AGENT = "uploadAgent";
    protected String UPLOAD_IS_FORCE_UPLOAD_TYPE = "uploadType";
    protected String UPLOAD_IS_RESEND_TYPE = "resendType";
    protected String COMPLETE_READ_FILES = "completeReadFiles";
    protected Messenger mService = null;
    protected final Messenger mAgent = new Messenger(new uploadHandler());

    protected boolean mServiceBound;

    protected HashMap<String, Long> uploadFiles = null;
    //protected boolean isAgentForceUpload = false;
    protected ArrayList<String> completeUploadFiles = new ArrayList<String>();
    protected String uploadFolder = null;
    protected boolean isDeleteAftUpload = false;
    protected String currentUploadFile = null;
    protected Long currentUploadFileSize = 0L;

    protected static final String AGENT_INFO = "agentInfo";
    protected static int UPLOAD_BUFFERED_SIZE = 200 *1000 * 1000;
    private static boolean isAbandon = false;
    private HashMap<String, ParcelFileDescriptor> writeFilesHM = new HashMap<String, ParcelFileDescriptor>();

    protected String ServiceName = "";
    protected ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            Log.i(TAG, "AprUploadAgent ServiceConnection: connect -> package" + className.getPackageName());
            mService = new Messenger(service);
            mServiceBound = true;
            deliverMessage(mAgent, UploadAgent.MSG_AGENT_SERVICE_BOUND, null);
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mServiceBound = false;
        }
    };
    /**
     * Handler of incoming messages from clients.
     */
    class uploadHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_AGENT_START:
                    //agentStart();
                break;
                case MSG_AGENT_SERVICE_BOUND:
                    // Log.i(TAG + ":MSG_AGENT_SERVICE_BOUND", "sendPrepareUploadFiles()");
                    sendPrepareUploadFiles(uploadFiles);
                break;
                case MSG_AGENT_START_WRITE:
                    Log.i(TAG, "handleMessage: MSG_AGENT_START_WRITE");
                    if (msg.obj != null){
                        if (msg.obj instanceof ParcelFileDescriptor){
                          if (uploadFiles != null) {
                            if (uploadFiles.size() > 0) {
                              if (msg.getData() != null) {
                                ExplorCurrentUploadData(msg.getData());
                                WriteFileDescriptor wFD = new WriteFileDescriptor();
                                writeFilesHM.put(currentUploadFile, (ParcelFileDescriptor)msg.obj);
                                //wFD.writeFileDescriptor = (ParcelFileDescriptor)msg.obj;
                                wFD.writeFileDescriptor = writeFilesHM.get(currentUploadFile);
                                new Thread(wFD).start();
                                deliverMessage(mService, UploadAgent.MSG_SERVICE_START_READ, null);
                              }
                            }
                          }
                        } else {
                            //Toast.makeText(getApplicationContext(), "UploadAgent:no Descriptor!", Toast.LENGTH_SHORT).show();
                        }
                    }
                    break;
                case MSG_AGENT_COMPLETE_WRITE:
                    //Toast.makeText(getApplicationContext(), "UploadAgent: Delete File!: " + isDeleteAftUpload, Toast.LENGTH_SHORT).show();
                    Bundle data = msg.getData();
                    if (data.containsKey(COMPLETE_READ_FILES)) {
                        CharSequence[] filesArr = data.getCharSequenceArray(COMPLETE_READ_FILES);
                        onCompleteWrite(filesArr);
                    } else {
                        onCompleteWrite(null);
                    }
                    break;
                case MSG_AGENT_SERVICE_OFF:
                    Log.i(TAG, "handleMessage: MSG_AGENT_SERVICE_OFF");
                    isAbandon = true;
                    onAgentServiceOff();
                break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private void onAgentServiceOff(){
     Iterator<String> fileNames = writeFilesHM.keySet().iterator();
     String fileName = "";
     while (fileNames.hasNext()) {
          fileName = fileNames.next();
          ParcelFileDescriptor fd = writeFilesHM.get(fileName);
          try{
            fd.close();
          } catch(IOException ex) {
              Log.i(TAG, "exception " + ex.toString());
          }
     }
     if (mServiceBound) {
         unbindService(mConnection);
         mServiceBound = false;
     }
     writeFilesHM.clear();
     uploadFiles.clear();
     stopSelf();
    }

    class WriteFileDescriptor implements Runnable{
        public ParcelFileDescriptor writeFileDescriptor;

        @Override
        public void run() {
            // TODO Auto-generated method stub
            FileInputStream fis = null;
            FileOutputStream fos = null;

            if (writeFileDescriptor != null && writeFileDescriptor.getFileDescriptor() != null) {
             try{
              if (currentUploadFile != null) {
                 File readedFile = new File(uploadFolder, currentUploadFile);
                 if (readedFile.exists()) {
                   fis = new FileInputStream(new File(uploadFolder, currentUploadFile));
                   fos = new FileOutputStream(writeFileDescriptor.getFileDescriptor());
                   streamCopy(fis, fos, currentUploadFileSize);
                 }
              }
             }catch(IOException ex) {
                 if (ex != null) {
                   if (ex.getMessage() != null) {
                     Log.i(TAG, "(186): " + ex.getMessage());
                   } else {
                         Log.i(TAG, "(188): " + ex.toString());
                         ex.printStackTrace();
                         StackTraceElement[] stmArr = ex.getStackTrace();
                         if (stmArr != null) {
                           for (int i = 0; i < stmArr.length; i++) {
                               Log.i(TAG, "at: " + stmArr[i].getFileName() + " " + stmArr[i].getClassName() + " " + stmArr[i].getMethodName() + " " + stmArr[i].getLineNumber());
                           }
                         }
                         Log.i(TAG, "(196): " + ex.toString());
                   }
                 } else {
                       Log.i(TAG, "IO Exception Happened in WriteFileDescriptor");
                 }
             } catch(Exception ex){
                 if (ex != null) {
                   if (ex.getMessage() != null) {
                     Log.i(TAG, "(204): " + ex.getMessage());
                   } else {
                     Log.i(TAG, "(206): " + ex.toString());
                   }
                 } else {
                   Log.i(TAG, "Exception Happened in WriteFileDescriptor");
                 }
             } finally{
                 synchronized(completeUploadFiles) {
                   Log.i(TAG, "add to completeUploadFiles: " + currentUploadFile);
                   completeUploadFiles.add(currentUploadFile);
                 }
                 try{
                     writeFileDescriptor.close();
                     if (fis != null) {
                       fis.close();
                     }
                     if (fos != null) {
                       fos.flush();
                       fos.close();
                     }
                 } catch(IOException ex){
                     if (ex != null) {
                       if (ex.getMessage() != null) {
                         Log.i(TAG, "(226): " + ex.getMessage());
                       } else {
                             Log.i(TAG, "(229): " + ex.toString());
                       }
                     } else {
                           Log.i(TAG, "Exception Happened in WriteFileDescriptor");
                     }
                 }
             }
           }
            Log.i(TAG, "Thread Stop(" + currentUploadFile + ")");
        }
    }


    public void agentStart(HashMap<String, Long> sendUploadFiles){
        if (mServiceBound) {
            Log.i(TAG, "agentStart: mserviceBound: true");
            sendPrepareUploadFiles(sendUploadFiles);
        } else {
            Log.i(TAG, "agentStart: mserviceBound: false");
            ComponentName comp = new ComponentName(UPLOAD_SERVICE_PACKAGE, UPLOAD_SERVICE);
            Intent i = new Intent().setComponent(comp);
            bindService(i, mConnection, Context.BIND_AUTO_CREATE);
        }
    }

    public void sendPrepareUploadFiles(HashMap<String, Long> sendUploadFiles) {
        if (!mServiceBound) return;

        deliverMessage(mService, UploadAgent.MSG_SERVICE_PREPARE_UPLOAD, GenerateUploadBundle(uploadFolder, sendUploadFiles, getServiceClassName(getApplicationContext())));
    }

    public void onCompleteWrite(CharSequence[] completeReadFiles){
       /*if (mServiceBound) {
            unbindService(mConnection);
            mServiceBound = false;
        }*/
       if (isDeleteAftUpload){
           deleteUploadedFiles(completeReadFiles);
       }
       if (uploadFiles.size() == 0) {
           Log.i(TAG, "onCompleteWrite");
           stopSelf();
       }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mAgent.getBinder();
    }

    protected void streamCopy(InputStream in, OutputStream out, Long fileSize)throws IOException{
            byte[] buffer = new byte[256];
            int bytesRead = 0;
            int total = 0;
            while(total < fileSize && !isAbandon){
                bytesRead = in.read(buffer);
                total += bytesRead;
                out.write(buffer, 0, bytesRead);
            }
            Log.i(TAG, "streamCopy() isAbandon: " + isAbandon);
    }


    @Override
    public void onStart(final Intent intent, int startId) {
        super.onStart(intent, startId);
        isAbandon = false;
        Context context = getApplicationContext();
        if (!mServiceBound) {
          checkBufferedSize(context);
        }

        IntentFilter filter=new IntentFilter();
        filter.addAction(IUploadAgent.UPLOAD_AGENT_RECEIVER);
        //this.registerReceiver(clientReceiver, filter);
        if (intent != null && intent.getExtras() != null) {

          if (intent.getExtras().get(UploadAgent.UPLOAD_FOLDER)!= null) {
            uploadFolder =(String)intent.getExtras().get(UploadAgent.UPLOAD_FOLDER);
          } else {
            uploadFolder = "";
          }

          boolean isForceUpload = false;
          if (intent.getExtras().get(UploadAgent.UPLOAD_IS_FORCE_UPLOAD) != null) {
              isForceUpload = (Boolean)intent.getExtras().get(UploadAgent.UPLOAD_IS_FORCE_UPLOAD);
          } else {
              isForceUpload = false;
          }
          Log.i(TAG, "onStart: isForceUpload: " + isForceUpload);

          boolean isResend = true;
          if (intent.getExtras().get(UploadAgent.UPLOAD_IS_RESEND) != null) {
            isResend = (Boolean)intent.getExtras().get(UploadAgent.UPLOAD_IS_RESEND);
          } else {
              isResend = true;
          }
          Log.i(TAG, "onStart: isResend: " + isResend);

          HashMap<String, Long> sendFileHM = null;
          if (intent.getExtras().get(UploadAgent.UPLOAD_FILES) != null) {
              sendFileHM= (HashMap<String, Long>)intent.getExtras().get(UploadAgent.UPLOAD_FILES);
              if (uploadFiles != null && uploadFiles.size() > 0) {
                  Iterator<String> fileIT = sendFileHM.keySet().iterator();
                  while(fileIT.hasNext()) {
                      String fileName = fileIT.next();
                      Long fileSize = sendFileHM.get(fileName);
                      if(!uploadFiles.containsKey(fileName)) {
                        uploadFiles.put(fileName, fileSize);
                      }

                  }
                  InsertDataRuner insRunner = new InsertDataRuner();
        		  insRunner.sendFileHM = copySendFileHM(sendFileHM);
                  insRunner.isForceUpload = isForceUpload;
                  insRunner.isResend = isResend;
                  new Thread(insRunner).start();
              } else {
                  uploadFiles = sendFileHM;
                  InsertDataRuner insRunner = new InsertDataRuner();
        		  insRunner.sendFileHM = copySendFileHM(sendFileHM);
                  insRunner.isForceUpload = isForceUpload;
                  insRunner.isResend = isResend;
                  new Thread(insRunner).start();
              }

          } else {
            sendFileHM = new HashMap<String, Long>();
            uploadFiles = new HashMap<String, Long>();
          }


          //====================
          // Resend Upload File which is not uploaded before
          //if (!isForceUpload) {
            String uploadFolder = this.getAgentUploadFolder(context);
            String label = this.getAgentLabel(context);
            if (!"N/A".equals(uploadFolder) && !"N/A".equals(label)){
                File folder = new File(uploadFolder);
                if (folder.exists()) {
                    File[] files = folder.listFiles();
                   if (files.length > 0) {
                     for (File uploadFile : files) {
                        if (uploadFile.getName().startsWith(label)) {
                           if (!uploadFiles.containsKey(uploadFile.getName())) {
                             uploadFiles.put(uploadFile.getName(), uploadFile.length());
                             sendFileHM.put(uploadFile.getName(), uploadFile.length());
                           }
                        }
                      }
                  }
                }
              }
          //}
          //====================
          if (intent.getExtras().get(UploadAgent.UPLOAD_IS_DELETE_AFT_COMPLETE) != null) {
            isDeleteAftUpload = (Boolean)intent.getExtras().get(UploadAgent.UPLOAD_IS_DELETE_AFT_COMPLETE);
          } else {
            isDeleteAftUpload = false;
          }
          Log.i(TAG, "onStart: agentStart()");
          agentStart(sendFileHM);
        } else {
            Log.i(TAG, "onStart: Start by AM");
            String uploadFolder = this.getAgentUploadFolder(context);
            String label = this.getAgentLabel(context);
            if (!"N/A".equals(uploadFolder) && !"N/A".equals(label)){
              File folder = new File(uploadFolder);
              if (folder.exists()) {
                File[] files = folder.listFiles();
                if (files.length > 0) {
                    this.uploadFolder = uploadFolder;
                    uploadFiles = new HashMap<String, Long>();
                    for (File uploadFile : files) {
                        if (uploadFile.getName().startsWith(label)) {
                          uploadFiles.put(uploadFile.getName(), uploadFile.length());
                        }
                    }
                    if (uploadFiles.size() > 0) {
                        Log.i(TAG, "onStart: agentStart()");
                        isDeleteAftUpload = true;
                        agentStart(uploadFiles);
                    } else {
                        Log.i(TAG, "onStart: Start by AM: No File need to Upload");
                    }
                } else {
                  Log.i(TAG, "onStart: Start by AM: No File in Folder");
                }
              } else {
                  Log.i(TAG, "onStart: Start by AM: folder(" + folder + ") is not exists");
              }
            } else {
                Log.i(TAG, "onStart: Start by AM: No Default Upload Folder and Label");
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy()");
        //this.unregisterReceiver(clientReceiver);
        if (mServiceBound) {
            try{
              unbindService(mConnection);
            } catch(Exception ex){
                Log.i(TAG, "onDestroy:unbindService() Msg: " + ex.toString());
            }

            mServiceBound = false;
        }
        isAbandon = false;
        if (uploadFiles != null) {
          uploadFiles.clear();
        }
    }
    /*
   public BroadcastReceiver clientReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.i(TAG, "onReceive: " + intent.getAction());
                if ( intent.getAction().equals(IUploadAgent.UPLOAD_AGENT_RECEIVER) ) {
                    if (intent.getSerializableExtra(UploadAgent.UPLOAD_FOLDER)!= null) {

                        uploadFolder =(String)intent.getStringExtra(UploadAgent.UPLOAD_FOLDER);

                    } else {
                        uploadFolder = "";
                    }
                    HashMap<String, Long> sendFileHM = null;
                    if (intent.getExtras().get(UploadAgent.UPLOAD_FILES) != null) {
                        sendFileHM = (HashMap<String, Long>)intent.getExtras().get(UploadAgent.UPLOAD_FILES);
                      if (uploadFiles != null && uploadFiles.size() > 0) {
                          Iterator<String> fileIT = sendFileHM.keySet().iterator();
                          while(fileIT.hasNext()) {
                              String fileName = fileIT.next();
                              Long fileSize = sendFileHM.get(fileName);
                              uploadFiles.put(fileName, fileSize);
                          }
                      } else {
                          uploadFiles = sendFileHM;
                      }
                    } else {
                        sendFileHM =  new HashMap<String, Long>();
                        uploadFiles = new HashMap<String, Long>();
                    }
                    if (intent.getExtras().get(UploadAgent.UPLOAD_IS_DELETE_AFT_COMPLETE) != null) {
                        isDeleteAftUpload = (Boolean)intent.getExtras().get(UploadAgent.UPLOAD_IS_DELETE_AFT_COMPLETE);
                    } else {
                        isDeleteAftUpload = false;
                    }
                    agentStart(sendFileHM);
                }
            }
    };*/


    protected Bundle GenerateUploadBundle(String folderName, HashMap<String, Long> files, String serviceClassName){
        Bundle data = new Bundle();
        data.putString(UPLOAD_FOLDER, folderName);
        if (files != null) {
            UploadLogDBHelper dbHelper = new UploadLogDBHelper(getApplicationContext());
             Iterator<String> fileIT = files.keySet().iterator();
             int uploadNum = files.size();
             CharSequence[] fileNameArr = new CharSequence[uploadNum];
             boolean[] uploadTypeArr = new boolean[uploadNum];
             boolean[] isResendArr = new boolean[uploadNum];
             long[] sizeArr = new long[uploadNum];
             String fileName = "";
             long fileSize = 0L;
             int idx = 0;
             //boolean isForceUpload = false;
             FileInfo fileInfo = null;
             while(fileIT.hasNext()) {
                 fileName = fileIT.next();
                 fileSize = files.get(fileName);
                 fileNameArr[idx] = fileName;
                 sizeArr[idx] = fileSize;
                 try{
                    synchronized(mDBLock) {
                       fileInfo = dbHelper.getFileInfo(fileName);
                    }
                   Log.i(TAG, "GenerateUploadBundle: getFileInfo(" + fileName + ")= isForceUpload: " + fileInfo.isForceUpload + " isResend: " + fileInfo.isResend);
                 } catch(Exception ex) {
                     Log.i(TAG, "GenerateUploadBundle: Exception Happen when isForceUploadFile(" + fileName + ") Msg: " + ex.toString());
                     fileInfo = new FileInfo();
                 }
                 uploadTypeArr[idx] = fileInfo.isForceUpload;
                 isResendArr[idx] = fileInfo.isResend;
                 idx ++;
             }
            if(dbHelper != null){
               dbHelper.close();
            }
            data.putCharSequenceArray(UPLOAD_FILE_NAMES, fileNameArr);
            data.putLongArray(UPLOAD_SIZES, sizeArr);
            data.putString(UPLOAD_AGENT_PACKAGE, this.getApplicationContext().getPackageName());
            data.putString(UPLOAD_AGENT, serviceClassName);
            data.putBooleanArray(UPLOAD_IS_FORCE_UPLOAD_TYPE, uploadTypeArr);
            data.putBooleanArray(UPLOAD_IS_RESEND_TYPE, isResendArr);
        }

        return data;
    }

    protected void ExplorCurrentUploadData(Bundle data){
        if (data != null) {
          this.currentUploadFile = (String)data.getCharSequence(UPLOAD_CURRENT_FILE_NAME);
          this.currentUploadFileSize = this.uploadFiles.get(this.currentUploadFile);
        }
    }

   public void deliverMessage(Messenger messager, int MsgType, Bundle data){
       if (messager != null) {
         Message msg = Message.obtain(null, MsgType, 0, 0);
         try {
          if (data != null) {
            msg.setData(data);
          }
          messager.send(msg);
         } catch (RemoteException e) {
           e.printStackTrace();
         }
       }
   }

   public static IUploadAgent getUploadAgent(Context context){
       return new UploadAgentHelper(context);
   }

   /*
   protected void deleteUploadedFiles(){
       Log.i(TAG, "folderPath: " + uploadFolder);
       if (uploadFiles != null){
        Iterator<String> fileNames = uploadFiles.keySet().iterator();
        String fileName = "";
        while(fileNames.hasNext()) {
            fileName = fileNames.next();
            File deleteFile = new File(uploadFolder, fileName);
            Log.i(TAG, "deleteFile: " + deleteFile.getAbsolutePath());
            boolean isDelete = deleteFile.delete();
            Log.i(TAG, "isDelete: " + isDelete);
        }
       }
    }*/


   protected void deleteUploadedFiles(CharSequence[] completeReadFiles){
       Log.i(TAG, "folderPath: " + uploadFolder);
       Context context = getApplicationContext();
       UploadLogDBHelper dbHelper = new UploadLogDBHelper(context);
       if (completeReadFiles != null) {
           for (int i = 0; i < completeReadFiles.length; i++) {
               String fileName = (String)completeReadFiles[i];
               File deleteFile = new File(uploadFolder, fileName);
                Log.i(TAG, "deleteFile(bundle): " + deleteFile.getAbsolutePath());
                  boolean isDelete = deleteFile.delete();
                  if (isDelete){
                     uploadFiles.remove(fileName);
                     synchronized(completeUploadFiles) {
                       completeUploadFiles.remove(fileName);
                     }
                     try{
                        synchronized(mDBLock) {
                          dbHelper.deleteUploadFileInfo(fileName);
                        }
                     } catch(Exception ex){
                           Log.i(TAG, "deleteUploadedFiles: Exception Happen when dbHelper.deleteForceUploadFile(" + fileName + ") Msg: " + ex.toString());
                     }
                  }
                   Log.i(TAG, "isDelete: " + isDelete);
           }
       } else {
           ArrayList<String> deleteFileList = new ArrayList<String>();
           synchronized(completeUploadFiles) {
             if (completeUploadFiles != null && completeUploadFiles.size() > 0){
               for (String fileName : completeUploadFiles){
                  File deleteFile = new File(uploadFolder, fileName);
                  Log.i(TAG, "deleteFile: " + deleteFile.getAbsolutePath());
                  boolean isDelete = deleteFile.delete();
                  if (isDelete){
                    uploadFiles.remove(fileName);
                    deleteFileList.add(fileName);
                  }
                   Log.i(TAG, "isDelete: uploadFiles" + isDelete);
                }
                  completeUploadFiles.clear();
                }
              }

           for(String deleteFile : deleteFileList){
              try{
                  synchronized(mDBLock) {
                    dbHelper.deleteUploadFileInfo(deleteFile);
                  }
               } catch(Exception ex){
                  Log.i(TAG, "deleteUploadedFiles completeReadFiles is null: Exception happen when dbHelper.deleteForceUploadFile(" + deleteFile + ") Msg: " + ex.toString());
               }
           }
       }
       ArrayList<String>UploadFileList = new ArrayList<String>();
       try{
           synchronized(mDBLock) {
             UploadFileList = dbHelper.getUploadFileList();
           }
       } catch(Exception ex){
           Log.i(TAG, "getUploadFileList: " + ex.toString());
       }
       for (String uploadFileName : UploadFileList){
           if (!new File(uploadFolder, uploadFileName).exists()){
               try{
                   synchronized(mDBLock) {
                     dbHelper.deleteUploadFileInfo(uploadFileName);
                   }
               } catch(Exception ex) {
                   Log.i(TAG, "Msg: deleteUploadFileInfo: " + ex.toString());
               }
           }

       }
       if(dbHelper != null){
           dbHelper.close();
        }
       Log.i(TAG, "deleteUploadedFiles: uploadFiles.size()" + uploadFiles.size());


    }

   protected String getAgentLabel(Context context){
        String AGENT_LABEL = "agent_label";
        SharedPreferences agentInfo = context.getSharedPreferences(AGENT_INFO, Context.MODE_MULTI_PROCESS);
        String agentLabel = agentInfo.getString(AGENT_LABEL, "N/A");
        return agentLabel;
   }

   protected String getAgentUploadFolder(Context context){
        String UPLOAD_FOLDER = "upload_folder";
        SharedPreferences agentInfo = context.getSharedPreferences(AGENT_INFO, Context.MODE_MULTI_PROCESS);
        String UploadFolder = agentInfo.getString(UPLOAD_FOLDER, "N/A");
        return UploadFolder;
   }

   protected String getServiceClassName(Context context){
        String SERVICE_CLASS_NAME = "service_class_name";
        SharedPreferences agentInfo = context.getSharedPreferences(AGENT_INFO, Context.MODE_MULTI_PROCESS);
        String serviceClassName = agentInfo.getString(SERVICE_CLASS_NAME, "N/A");
        return serviceClassName;
  }
   private void checkBufferedSize(Context context){
       File upFolder = new File(this.getAgentUploadFolder(context));

       if (upFolder.exists()) {
          File[] listFiles = upFolder.listFiles();
          long totalFileSize = 0;
          LinkedHashMap<Long, LinkedList<File>> lastModifyHM = new LinkedHashMap<Long, LinkedList<File>>();
          ArrayList<Long> timeList = new ArrayList<Long>();
          String label = this.getAgentLabel(context);
          String fileName = "";
         for (File file : listFiles) {
            if (!file.getName().startsWith(label)) {
              continue;
            }
            long lastModify = file.lastModified();
            if (!timeList.contains(lastModifyHM)) {
                timeList.add(lastModify);
            }
            totalFileSize += file.length();
            if (lastModifyHM.containsKey(lastModify)) {
                LinkedList<File> files = lastModifyHM.get(lastModify);
                files.add(file);
                lastModifyHM.put(lastModify, files);
            } else {
              LinkedList<File> files = new LinkedList<File>();
              files.add(file);
              lastModifyHM.put(lastModify, files);
            }
         }
         LongComparator longComparator = new LongComparator();
          Log.i(TAG, "totalFileSize: " + totalFileSize);
         if (totalFileSize <= UPLOAD_BUFFERED_SIZE){
          Log.i(TAG, "Buffered Safe!");
         } else {
          Long diffSize = totalFileSize - UPLOAD_BUFFERED_SIZE;
          Log.i(TAG, "diffSize: " + diffSize);
          UploadLogDBHelper dbHelper = new UploadLogDBHelper(context);
          Collections.sort(timeList, longComparator);
          Long deleteSize = 0L;
          for (Long time : timeList) {
              LinkedList<File> files = lastModifyHM.get(time);
                 for (File file : files){
                  if (deleteSize <= diffSize){
                      deleteSize += file.length();
                      Log.i(TAG, "Delete: " + file.getName());
                     try{
                        synchronized(mDBLock) {
                          dbHelper.deleteUploadFileInfo(file.getName());
                        }
                     } catch(Exception ex){
                           Log.i(TAG, "checkBufferedSize: Exception Happen when dbHelper.deleteForceUploadFile(" + file.getName() + ") Msg: " + ex.toString());
                     }
                      file.delete();
                  } else {
                      break;
                  }
                 }
                 if (deleteSize > diffSize){
                  break;
                 }
           }
            if(dbHelper != null){
               dbHelper.close();
            }
         }
       }
     }

   class InsertDataRuner implements Runnable{
	   private HashMap<String, Long> sendFileHM = null;
       boolean isForceUpload = false;
       boolean isResend = true;
        @Override
        public void run() {
          if (sendFileHM != null) {
            synchronized(mDBLock) {
              UploadLogDBHelper dbHelper = new UploadLogDBHelper(getApplicationContext());
              Iterator<String> fileIT = sendFileHM.keySet().iterator();
              while(fileIT.hasNext()) {
                 String fileName = fileIT.next();
                 try{
                      dbHelper.insertUploadFileInfo(fileName, isForceUpload, isResend);
                      Log.i(TAG, "InsertDataRuner: fileName: " + fileName + " isForceUpload: " + isForceUpload + " isResend: " + isResend);
                  } catch(Exception ex){
                    Log.i(TAG, "Exception Happen in (InsertDataRuner) dbHelper.insertForceUpload(" + fileName + ") Message: " + ex.toString());
                  }
                  if(dbHelper != null){
                   dbHelper.close();
                  }
              }
           }
        }
      }
   }
    private class LongComparator implements Comparator<Long>{

          public LongComparator() {
          }

          @Override
          public int compare(Long o1, Long o2) {
            if(o1 == o2) {
              return 0;
            } else if(o1 > o2) {
              return 1;
            } else {
              return -1;
		    }    
          }

        }


	   private HashMap<String, Long> copySendFileHM(HashMap<String, Long> sFileHM){
		   HashMap<String, Long> rtnFileHM = null;
		   if (sFileHM != null) {
			 rtnFileHM = new HashMap<String, Long>();
		     Set<String> fileNames = sFileHM.keySet();
		     for (String fileName : fileNames){
			   rtnFileHM.put(fileName, sFileHM.get(fileName));
		     }
		   }
		   return rtnFileHM;
	   }
}