/*
 * mainwnd.c: Main OSD Window Class
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include "mainwnd.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <utime.h>
#include <stdio.h>

extern char	m_sDefDir[_DEF_MAX_WIN][255];	// Default Directories
extern bool	m_bConfirmCopy;
extern bool	m_bConfirmDelete;
extern bool	m_bConfirmRemove;

cMainWnd::cMainWnd(void)
{
    pOSD = NULL;
    m_iCurrentPanel = 0;
    
    for (int i = 0; i < _DEF_MAX_WIN; i++)
    {
	pPanelWnd[i] = NULL;
    }
    
}

cMainWnd::~cMainWnd()
{

    for (int i = 0; i < _DEF_MAX_WIN; i++)
	if (pPanelWnd[i] != NULL)
	{
	    char *s;

	    pPanelWnd[i]->GetFolder(&s);
	    strcpy(m_sDefDir[i], s);
	    free(s);
	    
	    delete pPanelWnd[i];
	    pPanelWnd[i] = NULL;
	}
	
    if (pOSD)
	delete pOSD;
	
}

void cMainWnd::Show(void)
{
    int x = 0;
    int y = 0;
    
    x = (720 - (Setup.OSDWidth + 1)) / 2;
    y = (576 - Setup.OSDHeight) / 2;
    
//	dsyslog("X <%d> Y <%d>", x, y);

    pOSD = cOsdProvider::NewOsd(x, y);
    if (pOSD)
    {
      tArea Areas[] = { {0, 0, Setup.OSDWidth - 1, lineHeight - 1, 2 },
     {0, lineHeight, Setup.OSDWidth - 1, Setup.OSDHeight - lineHeight - 1, 2 },
     {0, Setup.OSDHeight - lineHeight, Setup.OSDWidth - 1, Setup.OSDHeight - 1, 2 }
    };
	
 pOSD->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
	
	CreatePanels();
	pPanelWnd[m_iCurrentPanel]->SetActive();
	RedrawAll();
	
	pOSD->Flush();
    }

}

cFileWnd *cMainWnd::GetActivePanel()
{
    return pPanelWnd[m_iCurrentPanel];
}

cFileWnd *cMainWnd::GetNextPanel(bool bChangeCurrentPanel)
{
    int i = m_iCurrentPanel;
    
    if (++i > _DEF_MAX_WIN - 1)
	i = 0;
	
    if (bChangeCurrentPanel)
	m_iCurrentPanel = i;
		    
    return pPanelWnd[i];
}

eOSState cMainWnd::ProcessKey(eKeys Key)
{
    eOSState state = cOsdObject::ProcessKey(Key);
    if (state == osUnknown)
    {
	bool bChanges = false;
	
	switch (Key & ~k_Repeat)
	{
	    case k5:
		bChanges = CopyFile();
		if (bChanges)
		    GetNextPanel()->Draw();
		break;
		bChanges = true;
	    case k6:
		bChanges = RemoveFile();
		if (bChanges)
		    GetNextPanel()->Draw();
		break;
		bChanges = true;
	    case k8:
		bChanges = DeleteFile();
		if (bChanges)
		    GetNextPanel()->Draw();
		break;
	    case kUp:
		bChanges = GetActivePanel()->GoUp();
		break;
	    case kDown:
		bChanges = GetActivePanel()->GoDown();
		break;
	    case kLeft:
		bChanges = GetActivePanel()->GoLeft();
		break;
	    case kRight:
		bChanges = GetActivePanel()->GoRight();
		break;
	    case kRed:
		GetActivePanel()->SetActive(false);
		RedrawAll(m_iCurrentPanel);
		
		GetNextPanel(true)->SetActive();
		    
		bChanges = true;
		break;
	    case kGreen:
		break;
	    case kYellow:
		break;
	    case kBlue:
		return osEnd;	// Exit
		break;
	    case kOk:
		bChanges = GetActivePanel()->GoIn();
		break;
	    case kBack:
		return osEnd;	// Exit
		break;
	    default:
		return state;
	}

	if (bChanges)
	{
	    RedrawAll(m_iCurrentPanel);
	    pOSD->Flush();
	}
    }
    
    return state;
}

void cMainWnd::CreatePanels(void)
{
    int iPanelWidth = p2c (Setup.OSDWidth) / _DEF_MAX_WIN;
    int iX = 0;
    int i;
    
    for (i = 0; i < _DEF_MAX_WIN - 1; i++)
    {
	pPanelWnd[i] = new cFileWnd(pOSD, iX, 0, iPanelWidth, p2l (Setup.OSDHeight) - 1, m_sDefDir[i]);
	iX += iPanelWidth;
    }
    
    pPanelWnd[_DEF_MAX_WIN - 1] = new cFileWnd(pOSD, iX, 0, p2c (Setup.OSDWidth) - iX, p2l (Setup.OSDHeight) - 1, m_sDefDir[_DEF_MAX_WIN - 1]);
}

void cMainWnd::RedrawAll(int iPanelNr)
{
    if (iPanelNr == -1)
    {
	for (int i = 0; i < _DEF_MAX_WIN; i++)
	{
	    pPanelWnd[i]->Draw();
	}
    }
    else if (iPanelNr >= 0 && iPanelNr < _DEF_MAX_WIN)
	pPanelWnd[iPanelNr]->Draw();
}

bool cMainWnd::CopyFile(bool bAsk)
{
    bool bReturn = false;
    
    if (!GetActivePanel()->isUpDirectory())
    {
	char *sFile		= NULL;
	char *sFolder		= NULL;
	char *sToFileName	= NULL;
	char *sToFullFormat	= NULL;

	GetActivePanel()->GetCurFullName(&sFile);
	GetNextPanel()->GetFolder(&sFolder);
	if (sFile && sFolder)
	{	
	    GetActivePanel()->GetFileItem(&sToFileName);
	    
	    if (strlen(sFolder) > 1)
    		asprintf(&sToFullFormat, "%s/%s", sFolder, sToFileName);
	    else
    		asprintf(&sToFullFormat, "%s%s", sFolder, sToFileName);
	
	    if (strcmp(sFile, sToFullFormat) != 0)
	    {
		bool bCopy = true;
		
		if (bAsk && m_bConfirmCopy)
		{
		    char *s;
		    char *sShowName;
	
		    GetActivePanel()->GetFileItemShow(&sShowName);
		    asprintf(&s, "Copy \"%s\" ?", sShowName);
		    bCopy = Confirm(s);
		    free(sShowName);
		    free(s);
		}
	    
		if (bCopy)
		{
		    int iRet = 0;
		    if (GetActivePanel()->isFile())
		    {
			dsyslog("VDRC: Copy file \"%s\" to \"%s\"", sFile, sToFullFormat);

			iRet = StartFunction(sFile, sToFullFormat, cFuncThread::func_copy_file);

			if ( iRet == -2 )
			{
			    unlink(sToFullFormat);
			}
			
			bReturn = ( iRet == 0 );

    			GetActivePanel()->RefreshActiveDir();
			GetNextPanel()->RefreshActiveDir();
		    }
		    else
		    if (GetActivePanel()->isDirectory())
		    {
			dsyslog("VDRC: Copy dir \"%s\" to \"%s\"", sFile, sToFullFormat);

			iRet = StartFunction(sFile, sToFullFormat, cFuncThread::func_copy_dir);

			if ( iRet == -2 )
			{
			    StartFunction(sToFullFormat, "", cFuncThread::func_delete_dir);
			}
			
			bReturn = ( iRet == 0 );
					    
    			GetActivePanel()->RefreshActiveDir();
			GetNextPanel()->RefreshActiveDir();
		    }
		}
	    }
	}
	
	if (sToFullFormat)
	    free(sToFullFormat);
	if (sToFileName)
	    free(sToFileName);
	if (sFile)
	    free(sFile);
	if (sFolder)
	    free(sFolder);

	ClearStatus();
    }
    
    return bReturn;
}

bool cMainWnd::DeleteFile(bool bAsk)
{
    bool bReturn = false;

    if (!GetActivePanel()->isUpDirectory())
    {
	char *sFile;
	
	GetActivePanel()->GetCurFullName(&sFile);
	
	if (sFile)
	{
    	    bool bDelete = true;
	    
    	    if (bAsk && m_bConfirmDelete)
    	    {
		char *s;
		char *sShowName;

		GetActivePanel()->GetFileItemShow(&sShowName);
		asprintf(&s, "Delete \"%s\" ?", sShowName);
		bDelete = Confirm(s);
		free(sShowName);
		free(s);
	    }
	    
	    if (bDelete)
	    {
		if (GetActivePanel()->isFile())
		{
		    dsyslog("VDRC: Delete file \"%s\"", sFile);
		    unlink(sFile);
    		    GetActivePanel()->RefreshActiveDir();
		    bReturn = true;
		}
		else
		if (GetActivePanel()->isDirectory())
		{
		    dsyslog("VDRC: Delete Directory \"%s\"", sFile);

		    bReturn = ( StartFunction(sFile, "", cFuncThread::func_delete_dir) == 0 );
		    
		    GetActivePanel()->RefreshActiveDir();
		    GetNextPanel()->RefreshActiveDir();
		}
	    }
	
	    free(sFile);
	}
    }
    
    return bReturn;
}

int cMainWnd::StartFunction(const char *sFile, const char *sToFile, int iFunction)
{
    int bReturn = 0;

    m_iReturnWords = -1;
    cpThread = new cFuncThread(pOSD, sFile, sToFile, iFunction, &m_iReturnWords);
		    
    while (cpThread->Active())
    {
	eKeys Key = kNone;
	Key = Interface->GetKey();
	if (Key == kBack)
	{
	    delete cpThread;
	    switch (iFunction)
	    {
		case cFuncThread::func_copy_file:
			dsyslog("VDRC: copy file was stoped");
			break;
		case cFuncThread::func_copy_dir:
			dsyslog("VDRC: copy dir was stoped");
			break;
		case cFuncThread::func_delete_dir:
			dsyslog("VDRC: delete dir was stoped");
			break;
	    }
	    bReturn = -2;
	    break;
	}
			
	usleep(30);
    }

    if (bReturn == 0)
	bReturn = m_iReturnWords;

    return bReturn;
}

bool cMainWnd::RemoveFile(void)
{
    bool bReturn = false;
    
    if (!GetActivePanel()->isUpDirectory())
    {
	char *sFile		= NULL;
	char *sFolder		= NULL;
	char *sToFileName	= NULL;
	char *sToFullFormat	= NULL;

	GetActivePanel()->GetCurFullName(&sFile);
	GetNextPanel()->GetFolder(&sFolder);
	if (sFile && sFolder)
	{	
	    GetActivePanel()->GetFileItem(&sToFileName);
	    
	    if (strlen(sFolder) > 1)
    		asprintf(&sToFullFormat, "%s/%s", sFolder, sToFileName);
	    else
    		asprintf(&sToFullFormat, "%s%s", sFolder, sToFileName);
	
	    if (strcmp(sFile, sToFullFormat) != 0)
	    {
		bool bRemove = true;
	    	    	
		if (m_bConfirmRemove)
		{
		    char *s;
		    char *sShowName;

		    GetActivePanel()->GetFileItemShow(&sShowName);
		    if (sShowName)
		    {
			asprintf(&s, "Remove \"%s\" ?", sShowName);
			bRemove = Confirm(s);
			free(sShowName);
			free(s);
		    }
		
		    if (bRemove)
		    {
			if (GetActivePanel()->isFile())
				dsyslog("VDRC: Remove file \"%s\" to \"%s\"", sFile, sFolder);
			else
			if (GetActivePanel()->isDirectory())
				dsyslog("VDRC: Remove dir \"%s\" to \"%s\"", sFile, sFolder);

			if (rename(sFile, sToFullFormat) == 0)
		    		bReturn = true;
			
			if (bReturn)    
			{
				GetActivePanel()->RefreshActiveDir();
    				GetNextPanel()->RefreshActiveDir();
			}
			else
			{
				bReturn = CopyFile(false);
				if (bReturn)
				bReturn = DeleteFile(false);
			}

		    }
		}
	    }
	}
	
	if (sToFullFormat)
	    free(sToFullFormat);
	if (sToFileName)
	    free(sToFileName);
	if (sFile)
	    free(sFile);
	if (sFolder)
	    free(sFolder);
    }
    
    return bReturn;
}

bool cMainWnd::Confirm(const char *s, int Seconds)
{
    bool bReturn = false;
    eKeys Key = kNone;

    ShowStatusText(s);

    Key = Wait(Seconds);

    if (RAWKEY(Key) == kOk)
	bReturn = true;

    ClearStatus();
    
    return bReturn;
}

eKeys cMainWnd::Wait(int Seconds)
{
  eKeys Key = kNone;
  if (Seconds == 0)
     Seconds = Setup.OSDMessageTime;
     
  time_t timeout = time(NULL) + Seconds;
  
  for (;;) {
      Key = Interface->GetKey();
      if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout)
         break;
      }
  return Key;
}

void cMainWnd::ShowStatusText(const char *s)
{
    pOSD->DrawRectangle(0, Setup.OSDHeight - lineHeight, Setup.OSDWidth - 1, Setup.OSDHeight - 1, clrGreen);
    pOSD->DrawText(5, Setup.OSDHeight - lineHeight, s, clrBlack, clrGreen, cFont::GetFont(fontOsd));
    
    pOSD->Flush();
}

void cMainWnd::ClearStatus(void)
{
    pOSD->DrawRectangle(0, Setup.OSDHeight - lineHeight, Setup.OSDWidth -1, Setup.OSDHeight - 1, clrGray50);
    
    pOSD->Flush();
}
