//
// WndScheduler.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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 2 of
// the License, or (at your option) any later version.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "Scheduler.h"
#include "Skin.h"
#include "Network.h"
#include "LiveList.h"
#include "WndScheduler.h"
#include "DlgScheduleItem.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_SERIAL(CSchedulerWnd, CPanelWnd, 0)

BEGIN_MESSAGE_MAP(CSchedulerWnd, CPanelWnd)
	//{{AFX_MSG_MAP(CSchedulerWnd)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_TIMER()
	ON_NOTIFY(NM_CUSTOMDRAW, IDC_SCHEDULE, OnCustomDrawList)
	ON_NOTIFY(NM_DBLCLK, IDC_SCHEDULE, OnDblClkList)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_SCHEDULE, OnSortList)
	ON_COMMAND(ID_SCHEDULER_ADD, OnSchedulerAdd)
	ON_UPDATE_COMMAND_UI(ID_SCHEDULER_ACTIVATE, OnUpdateSchedulerActivate)
	ON_COMMAND(ID_SCHEDULER_ACTIVATE, OnSchedulerActivate)
	ON_UPDATE_COMMAND_UI(ID_SCHEDULER_DEACTIVATE, OnUpdateSchedulerDeactivate)
	ON_COMMAND(ID_SCHEDULER_DEACTIVATE, OnSchedulerDeactivate)
	ON_UPDATE_COMMAND_UI(ID_SCHEDULER_EDIT, OnUpdateSchedulerEdit)
	ON_COMMAND(ID_SCHEDULER_EDIT, OnSchedulerEdit)
	ON_UPDATE_COMMAND_UI(ID_SCHEDULER_REMOVE, OnUpdateSchedulerRemove)
	ON_COMMAND(ID_SCHEDULER_REMOVE, OnSchedulerRemove)
	ON_WM_CONTEXTMENU()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSchedulerWnd construction

CSchedulerWnd::CSchedulerWnd()
{
	Create( IDR_SCHEDULERFRAME );
}

CSchedulerWnd::~CSchedulerWnd()
{
}

/////////////////////////////////////////////////////////////////////////////
// CSchedulerWnd message handlers

int CSchedulerWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if ( CPanelWnd::OnCreate( lpCreateStruct ) == -1 ) return -1;

	m_wndList.Create( WS_VISIBLE|LVS_ICON|LVS_AUTOARRANGE|LVS_REPORT|LVS_SHOWSELALWAYS,
		rectDefault, this, 100 );

	m_pSizer.Attach( &m_wndList );

	m_wndList.SendMessage( LVM_SETEXTENDEDLISTVIEWSTYLE,
		LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_LABELTIP,
		LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_LABELTIP );

	CBitmap bmBase;
	bmBase.LoadBitmap( IDB_SCHEDULER );

	m_gdiImageList.Create( 16, 16, ILC_MASK|ILC_COLOR16, 3, 1 );
	m_gdiImageList.Add( &bmBase, RGB( 0, 255, 0 ) );
	m_wndList.SetImageList( &m_gdiImageList, LVSIL_SMALL );

	m_wndList.InsertColumn( 0, _T("Action"), LVCFMT_LEFT, 250, -1 );
	m_wndList.InsertColumn( 1, _T("Date"), LVCFMT_LEFT, 200, -1 );
	m_wndList.InsertColumn( 2, _T("Time"), LVCFMT_CENTER, 100, -1 );
	m_wndList.InsertColumn( 3, _T("Active"), LVCFMT_CENTER, 100, -1 );
	m_wndList.InsertColumn( 4, _T("Status"), LVCFMT_CENTER, 100, -1);
	m_wndList.InsertColumn( 5, _T("Description"), LVCFMT_LEFT, 400, -1 );

	LoadState( _T("CSchedulerWnd"), TRUE );


	Update();

	return 0;
}

void CSchedulerWnd::OnDestroy() 
{
	Scheduler.Save();

	Settings.SaveList( _T("CSchedulerWnd"), &m_wndList );		
	SaveState( _T("CSchedulerWnd") );

	CPanelWnd::OnDestroy();
}

/////////////////////////////////////////////////////////////////////////////
// CSchedulerWnd operations

void CSchedulerWnd::Update(int nColumn, BOOL bSort)
{
	CLiveList pLiveList( 6 );	//A temp list

	//DWORD nNow = time( NULL );
	int nCount = 1;
	CQuickLock oLock( Scheduler.m_pSection ); //Anywhere is a read or write to SchedulerList this lock should be used
	for ( POSITION pos = Scheduler.GetIterator() ; pos ; nCount++ )
	{
		CScheduleItem* pSchItem = Scheduler.GetNext( pos );
		
		//Adding items we got from Scheduler to temp list and getting a handle
		//to modify their properties according to scheduler item.
		CLiveItem* pItem = pLiveList.Add( pSchItem );

		if (pSchItem->m_bActive)
			pItem->m_nImage = 1;
		else pItem->m_nImage = 2;

		switch (pSchItem->m_nAction)
		{
		case 1: pItem->Set( 0, _T("Bandwidth: Full Speed"));
			break;
		case 2: pItem->Set( 0, _T("Bandwidth: Reduced Speed"));
			break;
		case 3: pItem->Set( 0, _T("Bandwidth: Stop"));
			break;
		case 4: pItem->Set( 0, _T("System: Disconnect Dial-up Connection"));
			break;
		case 5: pItem->Set( 0, _T("System: Exit Shareaza"));
			break;
		case 6: pItem->Set( 0, _T("System: Turn Off the Computer"));
			break;
		}
		if (pSchItem->m_bEveryDay)
			pItem->Set( 1, _T("Every Day"));
		else
			pItem->Set( 1, pSchItem->m_sDate);

		pItem->Set( 2, pSchItem->m_sTime);

		if (pSchItem->m_bActive)
			pItem->Set( 3, _T("Active"));
		else
			pItem->Set( 3, _T("Inactive"));

		if ((pSchItem->m_bExecuted) && (!pSchItem->m_bEveryDay))
			pItem->Set( 4, _T("Done"));
		else
			if (pSchItem->m_bActive)
				pItem->Set( 4, _T("Waiting..."));
			else
				pItem->Set( 4, _T("Inactive"));

		pItem->Set( 5, pSchItem->m_sDescription);
	}
	
	//In case scheduler gave nothing
	if (nCount == 1)
	{
		CLiveItem* pDefault = pLiveList.Add( (LPVOID)0 );
		pDefault->Set( 0, _T("No Tasks Currently Scheduled") );
		pDefault->m_nImage = 0;
	}

	if ( nColumn >= 0 )
	{
		SetWindowLong( m_wndList.GetSafeHwnd(), GWL_USERDATA, 0 - nColumn - 1 );
	}

	pLiveList.Apply( &m_wndList, bSort );	//Putting items in the main list

	tLastUpdate = GetTickCount();	// Update time after it's done doing its work

}

CScheduleItem* CSchedulerWnd::GetItem(int nItem)
{
	if ( m_wndList.GetItemState( nItem, LVIS_SELECTED ) )
	{
		CQuickLock oLock( Scheduler.m_pSection );
		CScheduleItem* pItem = (CScheduleItem*)m_wndList.GetItemData( nItem );
		if ( Scheduler.Check( pItem ) ) return pItem;
	}

	return NULL;
}

/////////////////////////////////////////////////////////////////////////////
// CSchedulerWnd message handlers

void CSchedulerWnd::OnSize(UINT nType, int cx, int cy) 
{
	CPanelWnd::OnSize( nType, cx, cy );
	m_pSizer.Resize( cx );
	m_wndList.SetWindowPos( NULL, 0, 0, cx, cy, SWP_NOZORDER );
}

void CSchedulerWnd::OnTimer(UINT /*nIDEvent*/) 
{
	DWORD tTicks = GetTickCount();
	DWORD tDelay = 2 * Scheduler.GetCount();		// Delay based on size of list

	if ( ( tTicks - tLastUpdate ) > tDelay )
	{
		if ( tDelay < 2000 )
		{
			Update();							// Sort if list is under 1000
		}
		else
		{
			Update( -1, FALSE );				// Otherwise just refresh values
		}
	}
}

void CSchedulerWnd::OnCustomDrawList(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMLVCUSTOMDRAW* pDraw = (NMLVCUSTOMDRAW*)pNMHDR;

	if ( pDraw->nmcd.dwDrawStage == CDDS_PREPAINT )
	{
		*pResult = CDRF_NOTIFYITEMDRAW;
	}
	else if ( pDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT )
	{
		LV_ITEM pItem;
		pItem.mask		= LVIF_IMAGE;
		pItem.iItem		= pDraw->nmcd.dwItemSpec;
		pItem.iSubItem	= 0;
		m_wndList.GetItem( &pItem );

		switch ( pItem.iImage )
		{
		case 1:
			pDraw->clrText = RGB( 0, 127, 0 );
			break;
		case 2:
			pDraw->clrText = RGB( 255, 0, 0 );
			break;
		}

		*pResult = CDRF_DODEFAULT;
	}
}

void CSchedulerWnd::OnDblClkList(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
	OnSchedulerEdit();
	*pResult = 0;
}

void CSchedulerWnd::OnSortList(NMHDR* pNotifyStruct, LRESULT *pResult)
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNotifyStruct;
	CLiveList::Sort( &m_wndList, pNMListView->iSubItem );
	*pResult = 0;
}


void CSchedulerWnd::OnContextMenu(CWnd* /*pWnd*/, CPoint point) 
{
	Skin.TrackPopupMenu( _T("CSchedulerWnd"), point, ID_SCHEDULER_EDIT );
}

void CSchedulerWnd::OnUpdateSchedulerEdit(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_wndList.GetSelectedCount() == 1 );
}

void CSchedulerWnd::OnSchedulerEdit() 
{
	CQuickLock oLock( Scheduler.m_pSection );	//This means no task will be executed while dialog is open
	CScheduleItem* pRule = GetItem( m_wndList.GetNextItem( -1, LVIS_SELECTED ) );
	if ( ! pRule ) return;

	CScheduleItemDlg dlg( NULL, pRule );

	if ( dlg.DoModal() == IDOK )
	{
		Scheduler.Save();
		Update();
	}
}

void CSchedulerWnd::OnUpdateSchedulerRemove(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_wndList.GetSelectedCount() > 0 );
}

void CSchedulerWnd::OnSchedulerRemove() 
{
	CQuickLock oLock( Scheduler.m_pSection);

	for ( int nItem = -1 ; ( nItem = m_wndList.GetNextItem( nItem, LVIS_SELECTED ) ) >= 0 ; )
	{
		if ( CScheduleItem* pRule = GetItem( nItem ) )
		{
			Scheduler.Remove( pRule );
		}
	}
	
	Scheduler.Save();
	Update();
}

void CSchedulerWnd::OnSchedulerAdd() 
{
	CQuickLock oLock( Scheduler.m_pSection );
	CScheduleItemDlg dlg;

	if ( dlg.DoModal() == IDOK )
	{
		Scheduler.Save();
		Update();
	}
}

void CSchedulerWnd::OnSkinChange()
{
	CPanelWnd::OnSkinChange();
	Settings.LoadList( _T("CSchedulerWnd"), &m_wndList, -3 );
}

BOOL CSchedulerWnd::PreTranslateMessage(MSG* pMsg) 
{
	if ( pMsg->message == WM_KEYDOWN )
	{
		if ( pMsg->wParam == VK_DELETE )
		{
			OnSchedulerRemove();
			return TRUE;
		}
		else if ( pMsg->wParam == VK_INSERT )
		{
			PostMessage( WM_COMMAND, ID_SCHEDULER_ADD );
			return TRUE;
		}
	}

	return CPanelWnd::PreTranslateMessage( pMsg );
}

void CSchedulerWnd::OnUpdateSchedulerDeactivate(CCmdUI* pCmdUI) 
{	
	CQuickLock oLock( Scheduler.m_pSection );
	CScheduleItem* pItem = GetItem( m_wndList.GetNextItem( -1, LVIS_SELECTED ) );

	if ( ! pItem )
	{
		pCmdUI->Enable(FALSE);
		return;
	}

	pCmdUI->Enable( (m_wndList.GetSelectedCount() > 0 ) && (pItem->m_bActive));
}

void CSchedulerWnd::OnSchedulerDeactivate()
{
	CQuickLock oLock( Network.m_pSection );

	CScheduleItem* pItem = GetItem( m_wndList.GetNextItem( -1, LVIS_SELECTED ) );

	if ( ! pItem ) return;

	pItem->m_bActive = false;
	
	//PUT HERE (MoJo)

	Update();

}
void CSchedulerWnd::OnUpdateSchedulerActivate(CCmdUI* pCmdUI) 
{	
	CQuickLock oLock( Scheduler.m_pSection );

	CScheduleItem* pItem = GetItem( m_wndList.GetNextItem( -1, LVIS_SELECTED ) );


	if ( ! pItem )
	{
		pCmdUI->Enable(FALSE);
		return;
	}

	pCmdUI->Enable( (m_wndList.GetSelectedCount() > 0 ) && (!pItem->m_bActive));
}

void CSchedulerWnd::OnSchedulerActivate()
{
	CQuickLock oLock( Scheduler.m_pSection );

	CScheduleItem* pItem = GetItem( m_wndList.GetNextItem( -1, LVIS_SELECTED ) );


	if ( ! pItem ) return;

	CTime tNow = CTime::GetCurrentTime();

	if (!Scheduler.ScheduledTimePassed(&tNow,&pItem->m_tScheduleDateTime) || pItem->m_bEveryDay)
	{

		pItem->m_bActive = true;
		pItem->m_bExecuted = false;
	}
	else
	{
		
		OnSchedulerEdit();
	}
	
	Update();

}
