package ai.pai.lensman;

import android.app.Application;
import android.content.Context;
import android.widget.Toast;

import com.android.common.utils.FileUnzipTask;
import com.android.common.utils.LogHelper;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.utils.StorageUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;

import ai.pai.lensman.db.Preferences;
import ai.pai.lensman.utils.Constants;
import ai.pai.lensman.utils.PatchManager;
import ai.pai.lensman.utils.UrlContainer;

public class App extends Application{

    private static Context   mInstance;

    public static Context getAppContext(){
        return mInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this.getApplicationContext();
        if(!checkUsbPermission()){
            Toast.makeText(this,R.string.usb_permission_denied,Toast.LENGTH_SHORT).show();
        }
        checkCameraLibs();
        initImageLoader();
        new PatchManager().patch(this, UrlContainer.PATCH_CONFIG_URL,Constants.APP_PATCH_DIR+ File.separator+"patch-"+BuildConfig.VERSION_NAME+".dex","ai.pai.lensman.patch.PatchesInfoImpl");
        noMedia();
    }

    private boolean checkUsbPermission(){
        LogHelper.d("czy","checkUsbPermission starts");
        Process process = null;
        DataOutputStream os = null;
        try {
            String cmd = "chmod 777 " + getPackageCodePath();
            String cmd1 = "setenforce 0";
            String cmd2 = "chmod -R 0777 /dev/bus/usb" ;

            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes(cmd + "\n");
            os.writeBytes(cmd1 + "\n");
            os.writeBytes(cmd2 + "\n");
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
            return true;
        } catch (Exception e) {
            LogHelper.d("czy","checkUsbPermission exception occur -->"+e);
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
            }
        }
    }

    public void copyRawLibToSdcard(String dirPath){
        LogHelper.d("czy","copyRawLibToSdcard");
        Field[] raw = R.raw.class.getFields();
        for (Field r : raw) {
            try {
                int id=getResources().getIdentifier(r.getName(), "raw", getPackageName());
                if(r.getName().startsWith("camera")){
                    String path=dirPath+"/"+r.getName()+".so";
                    BufferedOutputStream rawZipWriter = new BufferedOutputStream((new FileOutputStream(new File(path))));
                    BufferedInputStream rawZipReader = new BufferedInputStream(getResources().openRawResource(id));
                    byte[] buff = new byte[20*1024];
                    int len;
                    while( (len = rawZipReader.read(buff)) > 0 ){
                        rawZipWriter.write(buff,0,len);
                    }
                    rawZipWriter.flush();
                    rawZipWriter.close();
                    rawZipReader.close();
                }
            } catch (Exception e) {
                LogHelper.d("czy","copyRawLibToSdcard exception occur -->"+e);
                e.printStackTrace();
            }
        }

    }

    private void checkCameraLibs(){
        String tmpLibDirPath = "/mnt/sdcard/lensman";
        File file = new File(tmpLibDirPath);
        file.mkdirs();
        final String unzipPath = tmpLibDirPath+File.separator+"so";
        String rawSoFilePath = tmpLibDirPath + File.separator + "camera.so";
        deleteDir(new File(unzipPath));
        new File(rawSoFilePath).delete();
        if(Preferences.getInstance().isCameraLibExist()){
            return ;
        }
        copyRawLibToSdcard(tmpLibDirPath);

        new FileUnzipTask(rawSoFilePath, unzipPath, new FileUnzipTask.FileUnzipListener() {
            @Override
            public void onUnzipSuccess(String zipFilePath, String unZipDir) {
                LogHelper.d("czy","onUnzipSuccess");
                ArrayList<String> libNames = new ArrayList<>();
                File libDir = new File(unZipDir);
                for(File file : libDir.listFiles()){
                    if(file.isFile()){
                        libNames.add(file.getName());
                    }else if(file.isDirectory()){
                        for(File subFile : file.listFiles()){
                            libNames.add(file.getName()+File.separator+subFile.getName());
                        }
                    }
                }
                Process process = null;
                DataOutputStream os = null;
                try {
                    String cmd0 = "";
                    for(String lib :libNames){
                        cmd0+="rm /system/lib/"+lib+"\n";
                    }
                    LogHelper.d("czy","cmd0="+cmd0);

                    String cmd = "chmod 777 " + getPackageCodePath();
                    String cmd2 = "chmod -R 0777 /dev/bus/usb" ;
                    String cmd3 = "mount -o rw,remount "+getSystemBlockPath()+" /system" ;
                    String cmd5 = "cp -fr /mnt/sdcard/lensman/so/.  /system/lib" ;

                    String cmd6 = "" ;
                    for(String lib :libNames){
                        cmd6+="chmod 0777 /system/lib/"+lib+"\n";
                    }
                    LogHelper.d("czy","cmd6="+cmd6);
                    process = Runtime.getRuntime().exec("su"); // 切换到root帐号
                    os = new DataOutputStream(process.getOutputStream());
                    os.writeBytes(cmd + "\n");
                    os.writeBytes(cmd0);
                    os.writeBytes(cmd2 + "\n");
                    os.writeBytes(cmd3 + "\n");
                    os.writeBytes(cmd5 + "\n");
                    os.writeBytes(cmd6 + "\n");
                    os.writeBytes("exit\n");
                    os.flush();
                    process.waitFor();
                    LogHelper.d("czy","camera lib so install success");
                    Preferences.getInstance().setCameraLibExist(true);
                } catch (Exception e) {
                    LogHelper.d("czy","camera lib so install error-->"+e);
                    Preferences.getInstance().setCameraLibExist(false);
                } finally {
                    try {
                        if (os != null) {
                            os.close();
                        }
                        new File(zipFilePath).delete();
                        deleteDir(new File(unZipDir));
                        if(process!=null){
                            process.destroy();
                        }
                    } catch (Exception e) {
                        LogHelper.d("czy","error occurs -->"+e);
                    }
                }
            }

            @Override
            public void onUnzipError(int errorCode, String zipFilePath, String unZipDir) {
                LogHelper.d("czy","onUnzipError");
                new File(zipFilePath).delete();
                deleteDir(new File(unZipDir));
            }
        }).startUnZip();

    }

    private String getSystemBlockPath(){
        String path = null;
        Process process = null;
        BufferedReader in = null;
        try {
            String cmd = "mount";
            process = Runtime.getRuntime().exec(cmd);
            in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                if(line.contains(" /system")){
                    path = line.substring(0,line.indexOf(" /system"));
                    LogHelper.d("czy","process result ="+line+"\n+");
                }
            }
        } catch (Exception e) {
            LogHelper.d("czy","getSystemBlockAddr exception occur -->"+e);
        } finally {
            try {
                if(in!=null){
                    in.close();
                }
                process.destroy();
            } catch (Exception e) {
            }
        }
        return path;
    }

    private static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            if (children != null) {
                for (int i = 0; i < children.length; i++) {
                    boolean success = deleteDir(new File(dir, children[i]));
                    if (!success) {
                        return false;
                    }
                }
            }
        }
        if (!dir.canRead() || !dir.canWrite()) {
            return false;
        }
        return dir.delete();
    }

    private void noMedia(){
        File noMedia = new File(Constants.APP_ROOT_DIR,".nomedia");
        if(noMedia.exists()){
            return;
        }
        try {
            File rootDir = new File(Constants.APP_ROOT_DIR);
            rootDir.mkdirs();
            noMedia.createNewFile();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    private void initImageLoader() {

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
                .memoryCacheExtraOptions(320, 320)
                .diskCacheExtraOptions(320, 320, null)
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .denyCacheImageMultipleSizesInMemory()
                .diskCacheFileNameGenerator(new Md5FileNameGenerator())
                .diskCache(new UnlimitedDiskCache(StorageUtils.getOwnCacheDirectory(this, Constants.TMP_DIR_NAME)))
                .diskCacheSize(50 * 1024 * 1024).tasksProcessingOrder(QueueProcessingType.LIFO)
                .memoryCache(new WeakMemoryCache()).memoryCacheSizePercentage(20)
                .threadPoolSize(4)
                .build();
        ImageLoader.getInstance().init(config);
    }

}
