/*
 * Copyright (C) 2012 Steven Luo
 *
 * 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 jackpal.androidterm.sample.pathbroadcasts;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


@Deprecated
public class PathReceiver extends BroadcastReceiver {

    public static final String ACTION_PATH_APPEND_BROADCAST = BuildConfig.TERM_APPLICATION_ID + ".broadcast.APPEND_TO_PATH";
    public static final String ACTION_PATH_PREPEND_BROADCAST = BuildConfig.TERM_APPLICATION_ID + ".broadcast.PREPEND_TO_PATH";

    /**
     * Called when a broadcast matching the declared intent filters is
     * received.
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        /* Unpack our sample bin/ and sbin/ if not already done */
        File binDir = setupBinDir(context);
        File sbinDir = setupSbinDir(context);

        String packageName = context.getPackageName();

        String action = intent.getAction();

        /**
         * You need to declare the permission
         * com.openmolcas_arm.permission.APPEND_TO_PATH
         * to receive this broadcast.
         */
        if (action.equals(ACTION_PATH_APPEND_BROADCAST)) {
            /* The directory we want appended goes into the result extras */
            Bundle result = getResultExtras(true);

            /**
             * By convention, entries are indexed by package name.
             *
             * If you need to impose an ordering constraint for some reason,
             * you may prepend a number to your package name -- for example,
             * 50-com.example.awesomebin or 00-net.busybox.android.
             */
            result.putString(packageName, binDir.getAbsolutePath());

            setResultCode(Activity.RESULT_OK);
        }

        /**
         * You need to declare the permission
         * com.openmolcas_arm.permission.PREPEND_TO_PATH
         * to receive this broadcast.
         *
         * This is intended for packages like BusyBox installers which need
         * to override existing system commands; otherwise, you should listen
         * for the APPEND_TO_PATH broadcast instead.
         */
        if (action.equals(ACTION_PATH_PREPEND_BROADCAST)) {
            /* The directory we want prepended goes into the result extras */
            Bundle result = getResultExtras(true);
            result.putString(packageName, sbinDir.getAbsolutePath());
            setResultCode(Activity.RESULT_OK);
        }
    }

    private File setupBinDir(Context context) {
        String dataDir = getDataDir(context);
        File binDir = new File(dataDir, "bin");
        if (!binDir.exists()) {
            try {
                binDir.mkdir();
                chmod("755", binDir.getAbsolutePath());
            } catch (Exception e) {
            }
        }

        File hello = new File(binDir, "hello");
        if (!hello.exists()) {
            try {
                InputStream src = context.getAssets().open("hello");
                FileOutputStream dst = new FileOutputStream(hello);
                copyStream(dst, src);
                chmod("755", hello.getAbsolutePath());
            } catch (Exception e) {
            }
        }

        return binDir;
    }

    private File setupSbinDir(Context context) {
        String dataDir = getDataDir(context);
        File sbinDir = new File(dataDir, "sbin");
        if (!sbinDir.exists()) {
            try {
                sbinDir.mkdir();
                chmod("755", sbinDir.getAbsolutePath());
            } catch (Exception e) {
            }
        }

        File ls = new File(sbinDir, "ls");
        if (!ls.exists()) {
            try {
                InputStream src = context.getAssets().open("ls");
                FileOutputStream dst = new FileOutputStream(ls);
                copyStream(dst, src);
                chmod("755", ls.getAbsolutePath());
            } catch (Exception e) {
            }
        }

        return sbinDir;
    }

    private String getDataDir(Context context) {
        /* On API 4 and later, you can just do this */
        // return context.getApplicationInfo().dataDir;

        String packageName = context.getPackageName();
        PackageManager pm = context.getPackageManager();
        String dataDir = null;
        try {
            dataDir = pm.getApplicationInfo(packageName, 0).dataDir;
        } catch (Exception e) {
            // Won't happen -- we know we're installed
        }
        return dataDir;
    }

    private void copyStream(OutputStream dst, InputStream src) throws IOException {
        byte[] buffer = new byte[4096];
        int bytesRead = 0;
        while ((bytesRead = src.read(buffer)) >= 0) {
            dst.write(buffer, 0, bytesRead);
        }
        dst.close();
    }

    private void chmod(String... args) throws IOException {
        String[] cmdline = new String[args.length + 1];
        cmdline[0] = "/system/bin/chmod";
        System.arraycopy(args, 0, cmdline, 1, args.length);
        new ProcessBuilder(cmdline).start();
    }
}
