/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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 com.n2hsu.launcher;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

import java.io.*;
import java.util.ArrayList;

public class Stats {
	private static final boolean DEBUG_BROADCASTS = false;
	private static final String TAG = "Launcher3/Stats";

	private static final boolean LOCAL_LAUNCH_LOG = true;

	public static final String ACTION_LAUNCH = "com.n2hsu.launcher.action.LAUNCH";
	public static final String PERM_LAUNCH = "com.n2hsu.launcher.permission.RECEIVE_LAUNCH_BROADCASTS";
	public static final String EXTRA_INTENT = "intent";
	public static final String EXTRA_CONTAINER = "container";
	public static final String EXTRA_SCREEN = "screen";
	public static final String EXTRA_CELLX = "cellX";
	public static final String EXTRA_CELLY = "cellY";

	private static final String LOG_FILE_NAME = "launches.log";
	private static final int LOG_VERSION = 1;
	private static final int LOG_TAG_VERSION = 0x1;
	private static final int LOG_TAG_LAUNCH = 0x1000;

	private static final String STATS_FILE_NAME = "stats.log";
	private static final int STATS_VERSION = 1;
	private static final int INITIAL_STATS_SIZE = 100;

	// TODO: delayed/batched writes
	private static final boolean FLUSH_IMMEDIATELY = true;

	private final Launcher mLauncher;

	DataOutputStream mLog;

	ArrayList<String> mIntents;
	ArrayList<Integer> mHistogram;

	public Stats(Launcher launcher) {
		mLauncher = launcher;

		loadStats();

		if (LOCAL_LAUNCH_LOG) {
			try {
				mLog = new DataOutputStream(mLauncher.openFileOutput(LOG_FILE_NAME, Context.MODE_APPEND));
				mLog.writeInt(LOG_TAG_VERSION);
				mLog.writeInt(LOG_VERSION);
			} catch (FileNotFoundException e) {
				Log.e(TAG, "unable to create stats log: " + e);
				mLog = null;
			} catch (IOException e) {
				Log.e(TAG, "unable to write to stats log: " + e);
				mLog = null;
			}
		}

		if (DEBUG_BROADCASTS) {
			launcher.registerReceiver(new BroadcastReceiver() {
				@Override
				public void onReceive(Context context, Intent intent) {
					android.util.Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
							+ intent.getStringExtra(EXTRA_INTENT));
				}
			}, new IntentFilter(ACTION_LAUNCH), PERM_LAUNCH, null);
		}
	}

	public void incrementLaunch(String intentStr) {
		int pos = mIntents.indexOf(intentStr);
		if (pos < 0) {
			mIntents.add(intentStr);
			mHistogram.add(1);
		} else {
			mHistogram.set(pos, mHistogram.get(pos) + 1);
		}
	}

	public void recordLaunch(Intent intent) {
		recordLaunch(intent, null);
	}

	public void recordLaunch(Intent intent, ShortcutInfo shortcut) {
		intent = new Intent(intent);
		intent.setSourceBounds(null);

		final String flat = intent.toUri(0);

		Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat);
		if (shortcut != null) {
			broadcastIntent.putExtra(EXTRA_CONTAINER, shortcut.container)
					.putExtra(EXTRA_SCREEN, shortcut.screenId).putExtra(EXTRA_CELLX, shortcut.cellX)
					.putExtra(EXTRA_CELLY, shortcut.cellY);
		}
		mLauncher.sendBroadcast(broadcastIntent, PERM_LAUNCH);

		incrementLaunch(flat);

		if (FLUSH_IMMEDIATELY) {
			saveStats();
		}

		if (LOCAL_LAUNCH_LOG && mLog != null) {
			try {
				mLog.writeInt(LOG_TAG_LAUNCH);
				mLog.writeLong(System.currentTimeMillis());
				if (shortcut == null) {
					mLog.writeShort(0);
					mLog.writeShort(0);
					mLog.writeShort(0);
					mLog.writeShort(0);
				} else {
					mLog.writeShort((short) shortcut.container);
					mLog.writeShort((short) shortcut.screenId);
					mLog.writeShort((short) shortcut.cellX);
					mLog.writeShort((short) shortcut.cellY);
				}
				mLog.writeUTF(flat);
				if (FLUSH_IMMEDIATELY) {
					mLog.flush(); // TODO: delayed writes
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void saveStats() {
		DataOutputStream stats = null;
		try {
			stats = new DataOutputStream(mLauncher.openFileOutput(STATS_FILE_NAME + ".tmp",
					Context.MODE_PRIVATE));
			stats.writeInt(STATS_VERSION);
			final int N = mHistogram.size();
			stats.writeInt(N);
			for (int i = 0; i < N; i++) {
				stats.writeUTF(mIntents.get(i));
				stats.writeInt(mHistogram.get(i));
			}
			stats.close();
			stats = null;
			mLauncher.getFileStreamPath(STATS_FILE_NAME + ".tmp").renameTo(
					mLauncher.getFileStreamPath(STATS_FILE_NAME));
		} catch (FileNotFoundException e) {
			Log.e(TAG, "unable to create stats data: " + e);
		} catch (IOException e) {
			Log.e(TAG, "unable to write to stats data: " + e);
		} finally {
			if (stats != null) {
				try {
					stats.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private void loadStats() {
		mIntents = new ArrayList<String>(INITIAL_STATS_SIZE);
		mHistogram = new ArrayList<Integer>(INITIAL_STATS_SIZE);
		DataInputStream stats = null;
		try {
			stats = new DataInputStream(mLauncher.openFileInput(STATS_FILE_NAME));
			final int version = stats.readInt();
			if (version == STATS_VERSION) {
				final int N = stats.readInt();
				for (int i = 0; i < N; i++) {
					final String pkg = stats.readUTF();
					final int count = stats.readInt();
					mIntents.add(pkg);
					mHistogram.add(count);
				}
			}
		} catch (FileNotFoundException e) {
			// not a problem
		} catch (IOException e) {
			// more of a problem

		} finally {
			if (stats != null) {
				try {
					stats.close();
				} catch (IOException e) {
				}
			}
		}
	}
}
