package com.hgsoft.debuglogshow;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Logcat implements Runnable {
    public final static String TAG = "Logcat";
    private Callback mCallback = null;
    private Thread mThread = null;
    private Process mProcess = null;
    private boolean mRun = false;

    public interface Callback {
        public void onLog(String log);
    }

    public Logcat() {
    }

    @Override
    public void run() {
        final String[] args = { "logcat", "|", "grep", DebugUtil.mainPid };
        InputStreamReader input = null;
        BufferedReader br = null;
        try {
            synchronized (this) {
                if (!mRun)
                    return;
                mProcess = Runtime.getRuntime().exec(args);
                input = new InputStreamReader(
                        mProcess.getInputStream());
            }
            br = new BufferedReader(input);
            String line;

            while ((line = br.readLine()) != null) {
                mCallback.onLog(line);
            }

        } catch (IOException e) {
        } finally {
            DebugUtil.close(input);
            DebugUtil.close(br);
        }
    }

    /**
     * Start a thread that will send logcat via a callback
     * @param callback
     */
    public synchronized void start(Callback callback) {
        if (callback == null)
            throw new IllegalArgumentException("callback should not be null");
        if (mThread != null || mProcess != null)
            throw new IllegalStateException("logcat is already started");
        mCallback = callback;
        mRun = true;
        mThread = new Thread(this);
        mThread.start();
    }

    /**
     * Stop the thread previously started
     */
    public synchronized void stop() {
        mRun = false;
        if (mProcess != null) {
            mProcess.destroy();
            mProcess = null;
        }
        try {
            mThread.join();
        } catch (InterruptedException e) {
        }
        mThread = null;
        mCallback = null;
    }

    /**
     * Writes the current app logcat to a file.
     *
     * @param filename The filename to save it as
     * @throws IOException
     */
    public static void writeLogcat(String filename) throws IOException {
        String[] args = { "logcat", "-v", "time", "-d" };

        Process process = Runtime.getRuntime().exec(args);

        InputStreamReader input = new InputStreamReader(process.getInputStream());

        FileOutputStream fileStream;
        try {
            fileStream = new FileOutputStream(filename);
        } catch( FileNotFoundException e) {
            return;
        }

        OutputStreamWriter output = new OutputStreamWriter(fileStream);
        BufferedReader br = new BufferedReader(input);
        BufferedWriter bw = new BufferedWriter(output);

        try {
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }
        }catch(Exception e) {}
        finally {
            DebugUtil.close(bw);
            DebugUtil.close(output);
            DebugUtil.close(br);
            DebugUtil.close(input);
        }
    }

    /**
     * Get the last 500 lines of the application logcat.
     *
     * @return the log string.
     * @throws IOException
     */
    public static String getLogcat() throws IOException {
        String[] args = { "logcat", "-v", "time", "-d", "-t", "500" };

        Process process = Runtime.getRuntime().exec(args);
        InputStreamReader input = new InputStreamReader(
                process.getInputStream());
        BufferedReader br = new BufferedReader(input);
        StringBuilder log = new StringBuilder();
        String line;

        while ((line = br.readLine()) != null)
            log.append(line + "\n");

        DebugUtil.close(br);
        DebugUtil.close(input);

        return log.toString();
    }
}
