/*
 * filewnd.c: File Window Class
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include "filewnd.h"
#include "global.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>

cFileItem::cFileItem(const char *sName, int iType)
{
    m_sName = strdup(sName);
    m_iType = iType;
}

cFileItem::~cFileItem()
{
    free(m_sName);
}

cFileWnd::cFileWnd(cOsd *osd, int x, int y, int width, int height, const char *folder)
{
    pOSD	= osd;
    iX		= x;		// OSD x
    iY		= y;		// OSD y
    iWidth	= width;	// OSD Width
    iHeight	= height;	// OSD Height
    m_bActive = false;
    m_iTopElem = 0;
    m_iCurrentElem = 0;
    strcpy(m_sFolder, folder);
    ReadActiveDir();
//    dsyslog("FileWnd <%d><%d>", iX, y);
}

cFileWnd::~cFileWnd()
{
}

void cFileWnd::SetActive(bool bActive)
{
    m_bActive = bActive;
}

bool cFileWnd::GoUp()
{
    bool bReturn = false;
    
    if (m_iCurrentElem > 0)
    {
	m_iCurrentElem--;
	bReturn = true;
    }
    else
    if (m_iTopElem > 0)
    {
	m_iTopElem--;
	bReturn = true;
    }
    
    return bReturn;
}

bool cFileWnd::GoDown()
{
    bool bReturn = false;
    
    if (m_iTopElem + m_iCurrentElem < m_lDir.Count() - 1)
    {
	if (m_iCurrentElem < iHeight - 2)
	{
	    m_iCurrentElem++;
	    bReturn = true;
	}
	else
	{
	    m_iTopElem++;
	    bReturn = true;
	}
    }
    
    return bReturn;
}

bool cFileWnd::GoLeft()
{
    bool bReturn = false;
    
    int iH = iHeight - 1;
    
    if (m_iTopElem > 0)
    {
	if (m_iTopElem > iH)
	    m_iTopElem -= iH;
	else
	    m_iTopElem = 0;
	    
	bReturn = true;
    }
    else
    if (m_iCurrentElem > 0)
    {
	m_iCurrentElem = 0;
	bReturn = true;
    }
    
    return bReturn;
}

bool cFileWnd::GoRight()
{
    bool bReturn = false;
    
    int iH = iHeight - 1;
    int iMaxElem = m_lDir.Count();
    
    if (iMaxElem > m_iTopElem + iH)
    {
	if (m_iTopElem + iH + m_iCurrentElem < iMaxElem)
	    m_iTopElem += iH;
	else
	    m_iTopElem = iMaxElem - iH;
	    
	bReturn = true;
    }
    else
    if (iMaxElem - m_iTopElem - 1 > m_iCurrentElem)
    {
	m_iCurrentElem = iMaxElem - m_iTopElem - 1;
	bReturn = true;
    }
    
    return bReturn;
}

bool cFileWnd::GoIn()
{
    bool bReturn = false;

    if (isDirectory())
    {
	char *s;
	
	GetCurFullName(&s);
	strcpy(m_sFolder, s);
	free(s);    

	bReturn = true;
    }
    else
    if (isUpDirectory())
    {
	int iStMax = strlen(m_sFolder);
	while (iStMax > 1 && m_sFolder[iStMax] != '/')
	    iStMax--;
	    
	m_sFolder[iStMax] = '\0';
	
	bReturn = true;
    }
    
    if (bReturn)
    {
	m_iTopElem = 0;
	m_iCurrentElem = 0;	
	ReadActiveDir();
    }
    
    return bReturn;
}

void cFileWnd::RefreshActiveDir()
{
    ReadActiveDir();
    
    int iMaxElem = m_lDir.Count() - 1;
    
    if (m_iTopElem > iMaxElem)
	m_iTopElem = iMaxElem;

    if (m_iTopElem + m_iCurrentElem > iMaxElem)
	m_iCurrentElem = iMaxElem - m_iTopElem;
}

void cFileWnd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg)
{
    if (x < iWidth && y < iHeight)
    {
pOSD->DrawText((iX + x) * charWidth + 2, (iY + y) * lineHeight, s, ColorFg, ColorBg, cFont::GetFont(fontOsd));
    }
}

void cFileWnd::Draw()
{
    // Clear Title
pOSD->DrawRectangle(iX * charWidth, iY * lineHeight,
		(iX + iWidth) * charWidth, (iY + 1) * lineHeight,
		clr_vdrc_bk);
    //Clear Panel
pOSD->DrawRectangle(iX * charWidth, (iY + 1) * lineHeight,
		(iX + iWidth) * charWidth, (iY + iHeight) * lineHeight,
		clr_vdrc_bk);
    DrawTitle();
    DrawDirItems();
}

void cFileWnd::DrawTitle()
{
    char *sShow;
    char *s = NULL;
    
    asprintf(&s, " %s ", m_sFolder);
    sShow = s;
    
    if (((int)strlen(s)) > iWidth)
    {
	sShow += (strlen(s) - iWidth + 2);
	sShow[0] = ' ';
	sShow[1] = '.';
	sShow[2] = '.';
    }
    int x = (iWidth - strlen(sShow)) / 2;
    
    DrawText(x, 0, sShow,
	    m_bActive ? 
		clr_vdrc_title_active : clr_vdrc_title_nactive,
	    m_bActive ?
		clr_vdrc_title_active_bk : clr_vdrc_title_nactive_bk);
    
    free(s);
}

void cFileWnd::DrawDirItems()
{
    int x = 0;

    for(int i = m_iTopElem; i < m_lDir.Count() && (i - m_iTopElem) < iHeight; i++)
    {
	int y = (i - m_iTopElem) + 1;
//	dsyslog("%d. %d %d", i, iWidth, strlen(s));
	char *s;
	GetFileItemShow(&s, i);
	
	if (i == (m_iCurrentElem + m_iTopElem) && m_bActive)
	{
pOSD->DrawRectangle((iX + x) * charWidth, (iY + y) * lineHeight, (iX + iWidth) * charWidth - 2, (iY + y + 1) * lineHeight - 1, clrCyan);
	    DrawText(x, y, s, clr_vdrc_item_sel, clr_vdrc_item_sel_bk);
	}
	else
	    DrawText(x, y, s, clr_vdrc_item_nsel, clr_vdrc_item_nsel_bk);

	free(s);
    }
}

bool cFileWnd::ReadActiveDir()
{
    bool bReturn = false;
    int iFolderLen = (int) strlen(m_sFolder);
    int iElems = 0;    
	 cReadLine reader;
    m_lDir.Clear();
/*
    DIR *dDir;
    
    dDir = opendir(m_sFolder);
    
    if (!dDir)
    {
	dDir = opendir("/");
	strcpy(m_sFolder, "/");
    }
	
    if (dDir)
    {
	struct dirent *fItem;
	struct stat stFile;
	
	while ( (fItem = readdir(dDir)) )
	{
	    if (!strcmp(fItem->d_name, "."))
		continue;
		
	    if (!strcmp(fItem->d_name, ".."))
	    {
		m_lDir.Add(new cFileItem("..", 0));
		continue;
	    }

	    char *sFName = NULL;
	    
	    if (strlen(m_sFolder) == 1)
		asprintf(&sFName, "%s", fItem->d_name);
	    else
	        asprintf(&sFName, "%s%s", m_sFolder, fItem->d_name);
		
	    stat(sFName, &stFile);

//	    if (S_ISDIR(
	    m_lDir.Add(new cFileItem(fItem->d_name, 1));
		
	    if (sFName)
		free(sFName);
	}
    }
*/
    char *sCMD = NULL;
    char sFA[] = "df";
//    dsyslog("VDRC: ReadActiveDir");    
    for (int i = 0; i < (int) strlen(sFA); i++)
    {
	asprintf(&sCMD, "find \"%s\" -follow -type %c -maxdepth 1 2>/dev/null | sort -df", m_sFolder, sFA[i]);
    
	FILE *fl = popen(sCMD, "r");
	if (fl)
	{
	    char *s;
	    while ( (s = reader.Read(fl)) != 0)
	    {
		s += iFolderLen;
		if (i == itemFile && iFolderLen > 1)
		    s++;
		if (m_sFolder[iFolderLen - 1] == '/' && i == 0)
	    	    s--;
	    
		if (((int)strlen(s)) > 1 || i != 0)
		    m_lDir.Add(new cFileItem(s, i));
		else
		    m_lDir.Add(new cFileItem("..", itemUpDir));
		    
		iElems++;
	    }
	
	    pclose(fl);
	
	    bReturn = true;
	}
	free(sCMD);
    }
    if (iElems == 0)
    {
	strcpy(m_sFolder, "/");
	bReturn = ReadActiveDir();
    }
    
    return bReturn;
}

bool cFileWnd::isDirectory()
{
    int iItem = (m_iCurrentElem + m_iTopElem);
    
    return (m_lDir.Get(iItem)->m_iType == itemDir);
}

bool cFileWnd::isFile()
{
    int iItem = (m_iCurrentElem + m_iTopElem);
    
    return (m_lDir.Get(iItem)->m_iType == itemFile);
}

bool cFileWnd::isUpDirectory()
{
    int iItem = (m_iCurrentElem + m_iTopElem);
    
    return (m_lDir.Get(iItem)->m_iType == itemUpDir);
}

void cFileWnd::GetFolder(char **sFolder)
{
    *sFolder = strdup(m_sFolder);
}

void cFileWnd::GetFileItem(char **sFileItem)
{
    int iItem = (m_iCurrentElem + m_iTopElem);
    
    if (isDirectory())
    {
	*sFileItem = strdup(m_lDir.Get(iItem)->m_sName + 1);
    }
    else
    if (isFile())
    {
	*sFileItem = strdup(m_lDir.Get(iItem)->m_sName);
    }
}

void cFileWnd::GetFileItemShow(char **sFileItem, int iItem)
{
    if (iItem == -1)
	iItem = (m_iCurrentElem + m_iTopElem);
	
    *sFileItem = (char *) calloc(iWidth, 1);
    strncpy(*sFileItem, m_lDir.Get(iItem)->m_sName, iWidth - 2);
    memset(*sFileItem + (iWidth - 2), '~', 1);
}

void cFileWnd::GetCurFullName(char **sFName)
{
    int iItem = (m_iCurrentElem + m_iTopElem);

    *sFName = NULL;
    if (isDirectory())
    {
	if (strlen(m_sFolder) == 1)
	    asprintf(sFName, "%s", m_lDir.Get(iItem)->m_sName);
	else
	    asprintf(sFName, "%s%s", m_sFolder, m_lDir.Get(iItem)->m_sName);
    }
    else
    if (isFile())
    {
	if (strlen(m_sFolder) == 1)
	    asprintf(sFName, "/%s", m_lDir.Get(iItem)->m_sName);
	else
	    asprintf(sFName, "%s/%s", m_sFolder, m_lDir.Get(iItem)->m_sName);
    }
}
