/*
 * Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
 *
 * This file is part of Loop Habit Tracker.
 *
 * Loop Habit Tracker is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * Loop Habit Tracker is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package org.isoron.androidbase;

import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.view.*;

import java.io.*;
import java.text.*;
import java.util.*;

import javax.inject.*;

public class AndroidBugReporter
{
    private final Context context;

    @Inject
    public AndroidBugReporter(@NonNull @AppContext Context context)
    {
        this.context = context;
    }

    /**
     * Captures and returns a bug report. The bug report contains some device
     * information and the logcat.
     *
     * @return a String containing the bug report.
     * @throws IOException when any I/O error occur.
     */
    @NonNull
    public String getBugReport() throws IOException
    {
        String logcat = getLogcat();
        String deviceInfo = getDeviceInfo();

        String log = "---------- BUG REPORT BEGINS ----------\n";
        log += deviceInfo + "\n" + logcat;
        log += "---------- BUG REPORT ENDS ------------\n";

        return log;
    }

    public String getDeviceInfo()
    {
        if (context == null) return "null context\n";

        WindowManager wm =
            (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        return
            String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME) +
            String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE) +
            String.format("OS Version: %s (%s)\n",
                System.getProperty("os.version"), Build.VERSION.INCREMENTAL) +
            String.format("OS API Level: %s\n", Build.VERSION.SDK) +
            String.format("Device: %s\n", Build.DEVICE) +
            String.format("Model (Product): %s (%s)\n", Build.MODEL,
                Build.PRODUCT) +
            String.format("Manufacturer: %s\n", Build.MANUFACTURER) +
            String.format("Other tags: %s\n", Build.TAGS) +
            String.format("Screen Width: %s\n",
                wm.getDefaultDisplay().getWidth()) +
            String.format("Screen Height: %s\n",
                wm.getDefaultDisplay().getHeight()) +
            String.format("External storage state: %s\n\n",
                Environment.getExternalStorageState());
    }

    public String getLogcat() throws IOException
    {
        int maxLineCount = 250;
        StringBuilder builder = new StringBuilder();

        String[] command = new String[]{ "logcat", "-d" };
        java.lang.Process process = Runtime.getRuntime().exec(command);

        InputStreamReader in = new InputStreamReader(process.getInputStream());
        BufferedReader bufferedReader = new BufferedReader(in);

        LinkedList<String> log = new LinkedList<>();

        String line;
        while ((line = bufferedReader.readLine()) != null)
        {
            log.addLast(line);
            if (log.size() > maxLineCount) log.removeFirst();
        }

        for (String l : log)
        {
            builder.append(l);
            builder.append('\n');
        }

        return builder.toString();
    }

    /**
     * Captures a bug report and saves it to a file in the SD card.
     * <p>
     * The contents of the file are generated by the method {@link
     * #getBugReport()}. The file is saved in the apps's external private
     * storage.
     *
     * @return the generated file.
     * @throws IOException when I/O errors occur.
     */
    @NonNull
    public void dumpBugReportToFile()
    {
        try
        {

            String date =
                new SimpleDateFormat("yyyy-MM-dd HHmmss", Locale.US).format(
                    new Date());

            if (context == null) throw new IllegalStateException();

            File dir = new AndroidDirFinder(context).getFilesDir("Logs");
            if (dir == null)
                throw new IOException("log dir should not be null");

            File logFile =
                new File(String.format("%s/Log %s.txt", dir.getPath(), date));
            FileWriter output = new FileWriter(logFile);
            output.write(getBugReport());
            output.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}
