//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// ctlListView.cpp - enhanced listview control
//
//////////////////////////////////////////////////////////////////////////

#include "pgAdmin3.h"

// wxWindows headers
#include <wx/wx.h>
#include <wx/imaglist.h>

// App headers
#include "ctl/ctlListView.h"
#include "utils/misc.h"

int wxCALLBACK
MyCompareFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr WXUNUSED(sortData))
{
	// inverse the order
	if (item1 < item2)
		return 1;
	if (item1 > item2)
		return -1;

	return 0;
}

ctlListView::ctlListView(wxWindow* p, int id, wxPoint pos, wxSize siz, long attr)
//	: wxListView(p, id, pos, siz, attr | wxLC_REPORT)
{
	nosort = false;
	autohint=false;
	order = 1;
	prev_col = -1;
	storelongstring = false;
#ifdef __WXGTK__	
	if (id==CTL_STATUSLIST) {
		if (iswayland) {
			SetBackgroundColour(wxTRANSPARENT);
			SetBackgroundStyle(wxBG_STYLE_PAINT);
		} //else SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
	}
#endif
	Create(p, id, pos, siz, attr | wxLC_REPORT);

	if (id!=CTL_STATUSLIST)
		Connect(wxID_ANY, wxEVT_LIST_COL_CLICK, wxListEventHandler(ctlListView::OnSortGrid));
		else  {
//			SetDoubleBuffered(true);
//			SetBackgroundStyle(wxBG_STYLE_PAINT);
//			Bind(wxEVT_ERASE_BACKGROUND, [] (wxEraseEvent&) {} );
		}
}
#include <map>
bool ctlListView::IsNumberColumn(const wxString& columnlabel) {
	bool asnum = false;
	if (columnlabel == _("CFS fragmentation") ||
		columnlabel == (_("Tuples inserted")) ||
		columnlabel == (_("Tuples updated")) ||
		columnlabel == (_("Tuples deleted")) ||
		columnlabel == (_("Tuples HOT updated")) ||
		columnlabel == (_("Live tuples")) ||
		columnlabel == (_("Dead tuples")) ||
		columnlabel == (_("CFS %")) ||
		columnlabel == (_("Autovacuum counter")) ||
		columnlabel == (_("Autoanalyze counter")) ||
		columnlabel == (_("Index Scans")) ||
		columnlabel == (_("Index Tuples Read")) ||
		columnlabel == (_("Index Tuples Fetched"))
		) {
		asnum = true;
		}
	return asnum;

}
void ctlListView::SortGrid(int colsort, bool isevent) {
	if (!nosort) {
		int col = colsort;
		if (col == prev_col && isevent) order = order * -1;
		int rows = GetItemCount();
		wxListItem listitem;
		listitem.SetMask(wxLIST_MASK_TEXT);
		GetColumn(col, listitem);
		wxString label = listitem.GetText();
		bool issize = label == _("Size");
		bool astext = true;
		if (IsNumberColumn(label)|| issize) astext = false;
		//sort numeric column
		if (astext) {
			std::multimap<wxString, int> mp;
			for (int i = 0; i < rows; i++) {
				wxString val = GetItemText(i, col);
				mp.insert(std::pair<wxString, int>(val, i));
			}
			// сопоставим сортированным значениям последовательность чисел для сортировки SortItems
			std::multimap<wxString, int>::iterator it = mp.begin();
			for (int i = 1; it != mp.end(); it++, i++) {  // выводим их
				int row = it->second; // row
				wxListView::SetItemData(row, (long)i * order);
			}

		}
		else
		{
			std::multimap<double, int> mp;
			double d;

			for (int i = 0; i < rows; i++) {
				wxString val = GetItemText(i, col);
				d = 0;
				if (val == "NaN") val = "0";
				if (val.ToCDouble(&d))
				{
					// это число
				}
				else
				{

					if (issize) // convert => MB
						d=ConvertSizeToMB(val);
				}
				mp.insert(std::pair<double, int>(d, i));
			}
			// сопоставим сортированным значениям последовательность чисел для сортировки SortItems
			std::multimap<double, int>::iterator it = mp.begin();
			for (int i = 1; it != mp.end(); it++, i++) {  // выводим их
				int row = it->second; // row
				wxListView::SetItemData(row, (long)i * order);
			}

		}

		SortItems(MyCompareFunction, 0);
		Refresh();
		prev_col = col;
	}
}
bool ctlListView::ReSort() {
	int ncols = GetColumnCount();
	if (prev_col >= 0 && prev_col < ncols)
			SortGrid(prev_col, false);
		else
			return false;
	return true;

}

void ctlListView::OnSortGrid(wxListEvent& event)
{
	int col = event.GetColumn();
	SortGrid(col, true);
}
long ctlListView::GetSelection()
{
	return GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
}

wxString ctlListView::GetTextLong(long row, long col)
{
	wxListItem item;
	item.SetId(row);
	item.SetColumn(col);
	item.SetMask(wxLIST_MASK_TEXT);
	GetItem(item);
	wxString v = item.GetText();
	if (storelongstring) {
		int len = v.Length();
		if (len == 200 && row >= 0 && col == 0 && row < longstring.size()) {
			return  longstring[row];
		}
	}
	return v;
};

wxString ctlListView::GetText(long row, long col)
{
	wxListItem item;
	item.SetId(row);
	item.SetColumn(col);
	item.SetMask(wxLIST_MASK_TEXT);
	GetItem(item);
	wxString v = item.GetText();
	return v;
};


void ctlListView::AddColumn(const wxString& text, int size, int format)
{
	if (size == wxLIST_AUTOSIZE || size == wxLIST_AUTOSIZE_USEHEADER)
	{
		InsertColumn(GetColumnCount(), text, format, size);
	}
	else
	{
		InsertColumn(GetColumnCount(), text, format, ConvertDialogToPixels(wxPoint(size, 0)).x);
	}
}


long ctlListView::AppendItem(int icon, const wxString& val, const wxString& val2, const wxString& val3, const wxString& val4)
{
	long idx = GetItemCount();
	long pos;
	pos = InsertItem(idx, val, icon);
	if (!val2.IsEmpty())
		SetItem(pos, 1, val2);
	if (!val3.IsEmpty())
		SetItem(pos, 2, val3);
	if (!val4.IsEmpty())
		SetItem(pos, 3, val4);

	return pos;
}
long ctlListView::AppendItemLong(int icon, const wxString& val, const wxString& val2, const wxString& val3, const wxString& val4)
{
	long idx = GetItemCount();
	long pos;
	if (storelongstring) {
		if (val.Length() > 200) {
			longstring.push_back(val);
			pos = InsertItem(idx, val.Mid(0, 200), icon);
		}
		else {
			longstring.push_back(wxEmptyString);
			pos = InsertItem(idx, val, icon);
		}
	}
	else
		pos = InsertItem(idx, val, icon);
	if (!val2.IsEmpty())
		SetItem(pos, 1, val2);
	if (!val3.IsEmpty())
		SetItem(pos, 2, val3);
	if (!val4.IsEmpty())
		SetItem(pos, 3, val4);

	return pos;
}


void ctlListView::CreateColumns(wxImageList* images, const wxString& left, const wxString& right, int leftSize)
{
	int rightSize;
	if (leftSize < 0)
	{
#ifdef __WXMAC__
		leftSize = rightSize = (GetParent()->GetSize().GetWidth() - 20) / 2;
#else
		leftSize = rightSize = GetSize().GetWidth() / 2;
#endif
	}
	else
	{
		if (leftSize)
			leftSize = ConvertDialogToPixels(wxPoint(leftSize, 0)).x;

#ifdef __WXMAC__
		rightSize = (GetParent()->GetSize().GetWidth() - 20) - leftSize;
#else
		rightSize = GetClientSize().GetWidth() - leftSize;
#endif
	}
	if (!leftSize)
	{
		InsertColumn(0, left, wxLIST_FORMAT_LEFT, GetClientSize().GetWidth());
	}
	else
	{
		InsertColumn(0, left, wxLIST_FORMAT_LEFT, leftSize);
		InsertColumn(1, right, wxLIST_FORMAT_LEFT, rightSize);
	}

	if (images)
		SetImageList(images, wxIMAGE_LIST_SMALL);
}


void ctlListView::CreateColumns(wxImageList* images, const wxString& str1, const wxString& str2, const wxString& str3, int leftSize)
{
	int rightSize;
	if (leftSize < 0)
	{
#ifdef __WXMAC__
		leftSize = rightSize = (GetParent()->GetSize().GetWidth() - 20) / 2;
#else
		leftSize = rightSize = GetSize().GetWidth() / 2;
#endif
	}
	else
	{
		if (leftSize)
			leftSize = ConvertDialogToPixels(wxPoint(leftSize, 0)).x;

#ifdef __WXMAC__
		rightSize = (GetParent()->GetSize().GetWidth() - 20) - leftSize;
#else
		rightSize = GetClientSize().GetWidth() - leftSize;
#endif
	}
	if (!leftSize)
	{
		InsertColumn(0, str1, wxLIST_FORMAT_LEFT, GetClientSize().GetWidth());
	}
	else
	{
		InsertColumn(0, str1, wxLIST_FORMAT_LEFT, leftSize);
		InsertColumn(1, str2, wxLIST_FORMAT_LEFT, rightSize / 2);
		InsertColumn(2, str3, wxLIST_FORMAT_LEFT, rightSize / 2);
	}

	if (images)
		SetImageList(images, wxIMAGE_LIST_SMALL);
}
