/**
 * 
 */
package com.asksven.android.common.kernelutils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.asksven.andoid.common.contrib.Util;
import com.asksven.android.common.CommonLogSettings;
import com.asksven.android.common.privateapiproxies.NetworkUsage;
import com.asksven.android.common.privateapiproxies.StatElement;
import com.asksven.android.common.shellutils.Exec;
import com.asksven.android.common.shellutils.ExecResult;
import com.asksven.android.common.utils.StringUtils;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.util.Log;


/**
 * @author sven
 * Parser for wakeup_sources
 * 
 ********************************** 
 * From pm_wakeup.h
 * struct wakeup_source - Representation of wakeup sources
 *
 * @total_time: Total time this wakeup source has been active.
 * @max_time: Maximum time this wakeup source has been continuously active.
 * @last_time: Monotonic clock when the wakeup source's was touched last time.
 * @prevent_sleep_time: Total time this source has been preventing autosleep.
 * @event_count: Number of signaled wakeup events.
 * @active_count: Number of times the wakeup sorce was activated.
 * @relax_count: Number of times the wakeup sorce was deactivated.
 * @expire_count: Number of times the wakeup source's timeout has expired.
 * @wakeup_count: Number of times the wakeup source might abort suspend.
 * @active: Status of the wakeup source.
 * @has_timeout: The wakeup source has been activated with a timeout.
 *	struct wakeup_source {
 *		const char 		*name;
 *		struct list_head	entry;
 *		spinlock_t		lock;
 *		struct timer_list	timer;
 *		unsigned long		timer_expires;
 *		ktime_t total_time;
 *		ktime_t max_time;
 *		ktime_t last_time;
 *		ktime_t start_prevent_time;
 *		ktime_t prevent_sleep_time;
 *		unsigned long		event_count;
 *		unsigned long		active_count;
 *		unsigned long		relax_count;
 *		unsigned long		expire_count;
 *		unsigned long		wakeup_count;
 *		bool			active:1;
 *		bool			autosleep_enabled:1;
 *	};
 *
 */
public class WakeupSources extends Wakelocks
{
    private final static String TAG ="WakeupSources";
    private static String FILE_PATH = "/sys/kernel/debug/wakeup_sources";
    //private static String FILE_PATH = "/sdcard/wakeup_sources.txt";
    
    public static ArrayList<StatElement> parseWakeupSources(Context context)
    {
    	Log.i(TAG, "Parsing " + FILE_PATH);
       	
    	String delimiter = String.valueOf('\t');
    	delimiter = delimiter + "+";
    	ArrayList<StatElement> myRet = new ArrayList<StatElement>();
    	// format 
    	// new [name	active_count	event_count		wakeup_count	expire_count	active_since	total_time	max_time	last_change	prevent_suspend_time]
    	ArrayList<String[]> rows = parseDelimitedFile(FILE_PATH, delimiter);

    	long msSinceBoot = SystemClock.elapsedRealtime();

		// list the running processes
		ActivityManager actvityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> procInfos = actvityManager.getRunningAppProcesses();

    	// start with 1
    	for (int i=1; i < rows.size(); i++ )
    	{
    		try
    		{
    			// times in file are milliseconds
    			String[] data = (String[]) rows.get(i);
    			String name = data[0].trim(); 						// name
    			int count = Integer.valueOf(data[1]);				// active_count
    			int expire_count = Integer.valueOf(data[4]);		// expire_count
    			int wake_count = Integer.valueOf(data[3]);			// wakeup_count
    			long active_since = Long.valueOf(data[5]);			// active_since
    			long total_time = Long.valueOf(data[6]);			// total_time
    			long sleep_time = Long.valueOf(data[9]);			// prevent_suspend_time
    			long max_time = Long.valueOf(data[7]);				// max_time
    			long last_change = Long.valueOf(data[8]);			// last_change
    			
				// post-processing of eventX-YYYY processes
				String details = "";

				// we start with a " here as that is the way the data comes from /proc
				if (name.startsWith("\"event"))
				{
					String process = name.replaceAll("\"", "");
					if (CommonLogSettings.DEBUG)
					{
						Log.d(TAG, "Pattern 'event' found in " + process);
					}
					
					int proc = 0;
					String[] parts = process.split("-");
					if (parts.length == 2)
					{
						try
						{
							proc = Integer.valueOf(parts[1]);
							if (CommonLogSettings.DEBUG)
							{
								Log.d(TAG, "Resolving proc name for 'event' " + proc);
							}
						}
						catch (Exception e)
						{
							Log.e(TAG, "Cound not split process name " + process);
						}
					}
					
					if (proc != 0)
					{
						// search for the process in the task list
						for (int psCount = 0; psCount < procInfos.size(); psCount++)
						{
							int id = procInfos.get(psCount).pid; 
							if ( id == proc)
							{
								String processName = procInfos.get(psCount).processName;

								details= processName; 
								String appName = "";

								String[] pkgList = procInfos.get(count).pkgList;
								for (int j=0; j < pkgList.length; j++)
								{
									if (details.length() > 0)
									{
										details += ", ";
									}
									details += pkgList[j];
								}

								if (CommonLogSettings.DEBUG)
								{
									Log.d(TAG, "Pattern 'event' resolved to " + details);
								}
							}
						}
					}
				}

    			NativeKernelWakelock wl = new NativeKernelWakelock(
    					name, details, count, expire_count, wake_count,
    					active_since, total_time, sleep_time, max_time,
    					last_change, msSinceBoot);
    			myRet.add(wl);
    		}
    		catch (Exception e)
    		{
    			// go on
    		}
    	}
    	return myRet;
    }
}