# -*- coding:utf-8 -*-
 
import wx
import wx.lib.mixins.listctrl as listmix
from list_mixin import ListCtrlSortMixin, FilterMixin, int_cmp, str_cmp, float_cmp
import os
import re
 
class ListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
	def __init__(self, parent, ID, pos=wx.DefaultPosition,
			size=wx.DefaultSize, style=0):
		wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
		listmix.ListCtrlAutoWidthMixin.__init__(self)
		self._createColumn()
		self.itemMap = []
		self.ref_dict = {}
 
 
 
	def _createColumn(self):
		raise NotImplementedError, 'ListCtrl is a abstract class.'
 
	def reset(self, data):
		self.DeleteAllItems()
		self.itemMap = []
		self.ref_dict = {}
		data.sort(cmp = lambda x, y: cmp(int(x[0]), int(y[0])))
		for idx, row in enumerate(data):
			self.ref_dict[int(row[0])] = idx
			self.itemMap.append(row)
			self.insert_data(idx, row)
 
	def insert_data(self, idx, data):
		self.InsertStringItem(idx, str(data[0]))
		self.SetItemData(idx, idx)	# for sort
		for col, txt in enumerate(data):
			if col == 0:
				continue
			self.SetStringItem(idx, col, str(txt))
 
def fl_cmp(l, r):
	l = l.split(':')
	r = r.split(':')
	cmpVal = cmp(l[0], r[0])
	if 0 == cmpVal:
		return cmp(int(l[1]), int(r[1]))
	return cmpVal
 
def ncalls_cmp(l, r):
	l = l.split('/')
	r = r.split('/')
	cmpVal = cmp(int(l[0]), int(r[0]))
	if 0 == cmpVal:
		return cmp(int(l[1]), int(r[1]))
	return cmpVal
 
class StatsListCtrl(ListCtrl, ListCtrlSortMixin):
	ID = 'ID'
	FUNC_NAME = 'func_name'
	FL = 'file:line'
	NCALLS = 'ncalls'
	TOTTIME = 'tottime'
	T_PERCALL = 't_percall'
	CUMTIME = 'cumtime'
	C_PERCALL = 'c_percall'
	columns = (ID, FUNC_NAME, FL, NCALLS, TOTTIME, \
		T_PERCALL, CUMTIME, C_PERCALL)
	sorters = (int_cmp, str_cmp, fl_cmp, ncalls_cmp, \
		float_cmp, float_cmp, float_cmp, float_cmp)
 
 
 
	def __init__(self, *a, **k):
		super(StatsListCtrl, self).__init__(*a, **k)
		ListCtrlSortMixin.__init__(self, StatsListCtrl.sorters)	# for sort
		self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.selected_func, self)
		self.selected_callback = None
 
	def reset(self, data):
		super(StatsListCtrl, self).reset(data)
		# set func_name and file:line columns autosize
		self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
		self.SetColumnWidth(2, wx.LIST_AUTOSIZE)
		# sort by cumtime
		self.SortListItems(6, False)
 
	def _createColumn(self):
		for i, col in enumerate(StatsListCtrl.columns):
			self.InsertColumn(i, col)
 
	def selected_func(self, evt):
		if self.selected_callback:
			self.selected_callback(evt)
 
class FilterStatsListCtrl(StatsListCtrl, FilterMixin):
	def __init__(self, *a, **k):
		StatsListCtrl.__init__(self, *a, **k)
		FilterMixin.__init__(self)
 
	def reset(self, data, needreplace = True):
		FilterMixin.reset(self, data, needreplace)
		StatsListCtrl.reset(self, data)
 
	def OnFilter(self, func_rest, file_rest):
		if func_rest:
			data = self.generic_filter(func_rest, self.data, 1, None)
		else:
			data = self.data
 
		if file_rest:
			def getfilename(s):
				return s.partition(':')[0]
			data = self.generic_filter(file_rest, data, 2, getfilename)
 
		self.reset(data, False)
 
	def OnAll(self):
		self.reset(self.data, False)
 
	def generic_filter(self, rest, data, col, getdata = None):
		try:
			p = re.compile(rest, re.I)
		except:
			from traceback import print_exc
			import sys
			print_exc(file = sys.stdout)
			return data
		if getdata:
			ret = [i for i in data if p.match(getdata(i[col]))]
		else:
			ret = [i for i in data if p.match(i[col])]
		return ret
 
class CallListCtrl(ListCtrl, ListCtrlSortMixin):
	ID = 'ID'
	FUNC_NAME = 'func_name'
	FL = 'file:line'
	NCALLS = 'ncalls'
	TOTTIME = 'tottime'
	columns = (ID, FUNC_NAME, FL, NCALLS, TOTTIME)
	sorters = (int_cmp, str_cmp, fl_cmp, ncalls_cmp, float_cmp)
 
	def __init__(self, *a, **k):
		super(CallListCtrl, self).__init__(*a, **k)
		ListCtrlSortMixin.__init__(self, CallListCtrl.sorters)
		self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.selected_func, self)
 
		self.data_list = []
 
	def reset(self, data):
		tmp_data = []
		for i in data:
			tmp_data.append(i)
 
		from statsmodel import make_calls_data
		data = make_calls_data(data)
 
		self.data_list = [0]*(len(data)+1)
		for i,a in enumerate(data):
			self.data_list[int(a[0])] = tmp_data[i]
 
		super(CallListCtrl, self).reset(data)
		self.SortListItems(4, False)
 
	def Clear(self):
		self.reset({})
 
	def _createColumn(self):
		for i, col in enumerate(CallListCtrl.columns):
			self.InsertColumn(i, col)
 
	def selected_func(self, evt):
		if self.selected_callback:
			idx = int(self.GetItemText(evt.GetIndex()))
			self.selected_callback(self.data_list[idx])
 
 
class HistoryListCtrl(wx.ListCtrl):
	ID = 'ID'
	FUNC_NAME = 'func_name'
	FL = 'file:line'
	columns = (ID, FUNC_NAME, FL)
	widths = (50,150,150)
 
	def __init__(self, *a, **k):
		super(HistoryListCtrl, self).__init__(*a, **k)
		self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.selected_func, self)
		self.data_list = []
		self.length = 0
		self.isHistoryHit = False
		self.iterator = 0
		self.focus_id = 0
		self._createColumn()
 
	def insert_data(self, idx, data):
		self.InsertStringItem(0, str(idx))
		self.SetStringItem(0, 1, str(data[0]))
		self.SetStringItem(0, 2, str(data[1]))
 
	def my_focus(self, itemid):
		self.focus_id = itemid
		self.Focus(self.focus_id)
		self.Select(self.focus_id)
 
	def insert(self, data):
		while self.iterator + 1 < self.length:
			self.pop()
		self.data_list.append(data)
		data = (data[2], os.path.basename(data[0]) + ':' + str(data[1]))
		self.insert_data(self.length, data)
		self.my_focus(0)
		self.length += 1
		self.iterator = self.length
 
	def Clear(self):
		while self.length > 0:
			self.pop()
		self.iterator = 0
		self.focus_id = 0
 
	def pop(self):
		self.data_list.pop()
		self.length -= 1
		self.DeleteItem(0)
 
	def _createColumn(self):
		for i, col in enumerate(HistoryListCtrl.columns):
			self.InsertColumn(i, col, width = HistoryListCtrl.widths[i])
 
	def Redo(self):
		if self.iterator >= self.length-1:
			return
		self.iterator += 1
		self.my_focus(self.focus_id - 1)
 
	def Undo(self):
		if self.iterator <= 0:
			return
		self.iterator -= 1
		self.my_focus(self.focus_id + 1)
 
	def selected_func(self, evt):
		if self.selected_callback:
			self.isHistoryHit = True
			self.focus_id = int(evt.GetIndex())
			idx = int(self.GetItemText(evt.GetIndex()))
			self.iterator = idx
			self.selected_callback(self.data_list[idx])
 
class LoadedListCtrl(wx.ListCtrl):
	ID = 'ID'
	FILE_NAME = 'file_name'
	PATH = 'path'
	columns = (ID, FILE_NAME, PATH)
	widths = (50,100,200)
 
	def __init__(self, *a, **k):
		super(LoadedListCtrl, self).__init__(*a, **k)
		self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.selected_func, self)
		self.stats_list = []
		self.data_list = []
		self.file_dict = {}
		self.lenght = 0
		self.iterator = 0
		self.focus_id = 0
		self._createColumn()
 
	def insert(self, data, stats):
		print data
		if self.file_dict.has_key(data):
			self.stats_list[self.file_dict[data]] = stats
		else:
			self.file_dict[data] = self.lenght
			self.data_list.append(data)
			self.stats_list.append(stats)
			self.lenght += 1
			self.insert_data(self.lenght, data)
 
	def insert_data(self, idx, data):
		self.InsertStringItem(idx-1, str(idx))
		self.SetStringItem(idx-1, 1, str(data[0]))
		self.SetStringItem(idx-1, 2, str(data[1]))
 
	def selected_func(self, evt):
		self.focus_id = int(evt.GetIndex())
		idx = int(self.GetItemText(evt.GetIndex()))
		self.selected_callback(self.stats_list[idx-1])
 
	def _createColumn(self):
		for i, col in enumerate(LoadedListCtrl.columns):
			self.InsertColumn(i, col, width = LoadedListCtrl.widths[i])