#include "menudetailview.h"
#include "services/epgsearch.h"
#include <sstream>
#include <iostream>
#include <dirent.h>
#include <vector>

cNopacityMenuDetailView::cNopacityMenuDetailView(cOsd *osd) {
    this->osd = osd;
    hasScrollbar = false;
}

cNopacityMenuDetailView::~cNopacityMenuDetailView(void) {
    delete font;
    if (fontHeader)
        delete fontHeader;
    if (fontHeaderLarge)
        delete fontHeaderLarge;
}

void cNopacityMenuDetailView::SetGeometry(int x, int width, int height, int top, int contentBorder, int headerHeight) {
    this->x = x;
    this->width = width;
    this->height = height;
    this->top = top;
    this->border = contentBorder;
    this->headerHeight = headerHeight;
    contentHeight = height - headerHeight;
}

int cNopacityMenuDetailView::DrawTextWrapper(cTextWrapper *wrapper, int top) {
    int linesText = wrapper->Lines();
    int textHeight = font->Height();
    int currentHeight = 0;
    for (int i=0; i < linesText; i++) {
        currentHeight = (i+1)*textHeight + top;
        pixmapContent->DrawText(cPoint(2*border, currentHeight), wrapper->GetLine(i), Theme.Color(clrMenuFontDetailViewText), clrTransparent, font);
    }
    return currentHeight + textHeight;
}

double cNopacityMenuDetailView::ScrollbarSize(void) {
    double barSize = (double)contentHeight / (double)contentDrawPortHeight;
    return barSize;
}

double cNopacityMenuDetailView::Offset(void) {
    double offset;
    if (((-1)*pixmapContent->DrawPort().Point().Y() + contentHeight + font->Height()) > contentDrawPortHeight)
        offset = (double)1 - ScrollbarSize();
    else
        offset = (double)((-1)*pixmapContent->DrawPort().Point().Y())/(double)((-1)*pixmapContent->DrawPort().Point().Y() + contentHeight);
    return offset;

}
bool cNopacityMenuDetailView::Scroll(bool Up, bool Page) {

    int aktHeight = pixmapContent->DrawPort().Point().Y();
    int totalHeight = pixmapContent->DrawPort().Height();
    int screenHeight = pixmapContent->ViewPort().Height();
    int lineHeight = font->Height();
    bool scrolled = false;
    if (Up) {
        if (Page) {
            int newY = aktHeight + screenHeight;
            if (newY > 0)
                newY = 0;
            pixmapContent->SetDrawPortPoint(cPoint(0, newY));
            scrolled = true;
        } else {
            if (aktHeight < 0) {
                pixmapContent->SetDrawPortPoint(cPoint(0, aktHeight + lineHeight));
                scrolled = true;
            }
        }
    } else {
        if (Page) {
            int newY = aktHeight - screenHeight;
            if ((-1)*newY > totalHeight - screenHeight)
                newY = (-1)*(totalHeight - screenHeight);
            pixmapContent->SetDrawPortPoint(cPoint(0, newY));
            scrolled = true;
        } else {
            if (totalHeight - ((-1)*aktHeight + lineHeight) > screenHeight) {
                pixmapContent->SetDrawPortPoint(cPoint(0, aktHeight - lineHeight));
                scrolled = true;
            }
        }
    }
    return scrolled;
}

//---------------cNopacityMenuDetailEventView---------------------

cNopacityMenuDetailEventView::cNopacityMenuDetailEventView(cOsd *osd, const cEvent *Event) : cNopacityMenuDetailView(osd) {
    event = Event;
    numEPGPics = 0;
}

cNopacityMenuDetailEventView::~cNopacityMenuDetailEventView(void) {
    osd->DestroyPixmap(pixmapHeader);
    osd->DestroyPixmap(pixmapContent);
    osd->DestroyPixmap(pixmapLogo);
}

void cNopacityMenuDetailEventView::CreatePixmaps(void) {
    pixmapHeader =  osd->CreatePixmap(3, cRect(x, top, width, headerHeight));
    pixmapContent = osd->CreatePixmap(3, cRect(x, top + headerHeight, width, contentHeight),
                                         cRect(0, 0, width, contentDrawPortHeight));
    pixmapLogo =    osd->CreatePixmap(4, cRect(x + border, top + max((headerHeight-config.logoHeight)/2,1), config.detailViewLogoWidth, config.detailViewLogoHeight));

    pixmapHeader->Fill(clrTransparent);
    pixmapHeader->DrawRectangle(cRect(0, headerHeight - 2, width, 2), Theme.Color(clrMenuBorder));
    pixmapContent->Fill(clrTransparent);
    pixmapLogo->Fill(clrTransparent);
    
}

void cNopacityMenuDetailEventView::SetFonts(void) {
    font = cFont::CreateFont(config.fontName, contentHeight / 25 + 3 + config.fontDetailView);
    fontHeaderLarge = cFont::CreateFont(config.fontName, headerHeight / 4 + config.fontDetailViewHeaderLarge);
    fontHeader = cFont::CreateFont(config.fontName, headerHeight / 6 + config.fontDetailViewHeader);
}

void cNopacityMenuDetailEventView::SetContent(void) {
    if (event) {
        content.Set(event->Description(), font, width - 4 * border);
        if (config.displayRerunsDetailEPGView) {
            LoadReruns();
        }
    }
}

void cNopacityMenuDetailEventView::SetContentHeight(void) {
    int lineHeight = font->Height();
    int linesContent = content.Lines() + 1;
    if (config.displayRerunsDetailEPGView) {
        linesContent+= reruns.Lines() + 2;
    }
    int heightContentText = linesContent * lineHeight;
    
    if (config.displayAdditionalEPGPictures) {
        heightContentText += HeightEPGPics();
    }

    if (heightContentText > contentHeight) {
        contentDrawPortHeight = heightContentText;
        hasScrollbar = true;
    } else {
        contentDrawPortHeight = contentHeight;  
    }
}

int cNopacityMenuDetailEventView::HeightEPGPics(void) {
    int numPicsAvailable = 0;
    for (int i=1; i <= config.numAdditionalEPGPictures; i++) {
        cString epgimage;
        if (config.epgImagePathSet) {
            epgimage = cString::sprintf("%s%d_%d.jpg", *config.epgImagePath, event->EventID(), i);
        } else {
            epgimage = cString::sprintf("%s%d_%d.jpg", *config.epgImagePathDefault, event->EventID(), i);
        }
        FILE *fp = fopen(*epgimage, "r");
        if (fp) {
            numPicsAvailable = i;
            fclose(fp);
        } else {
            break;
        }
    }
    numEPGPics = numPicsAvailable;
    int picsPerLine = width / (config.epgImageWidthLarge + border);
    int picLines = numPicsAvailable / picsPerLine;
    if (numPicsAvailable%picsPerLine != 0)
        picLines++;
    return picLines * (config.epgImageHeightLarge + border) + 2*border;
}

void cNopacityMenuDetailEventView::Render(void) {
    DrawHeader();
    int currentHight = DrawTextWrapper(&content, 0);
    if (config.displayRerunsDetailEPGView) {
        currentHight = DrawTextWrapper(&reruns, currentHight);
    }
    if (config.displayAdditionalEPGPictures) {
        DrawEPGPictures(currentHight);
    }
}

void cNopacityMenuDetailEventView::DrawHeader(void) {
    cImageLoader imgLoader;
    int logoWidth = config.detailViewLogoWidth;
    cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
    if (channel && channel->Name() && imgLoader.LoadLogo(channel->Name(), logoWidth, config.detailViewLogoHeight)) {        
        pixmapLogo->DrawImage(cPoint(0, max((headerHeight - config.detailViewLogoHeight - border)/2, 0)), imgLoader.GetImage());
    }
    int widthTextHeader = width - 4 * border - logoWidth;
    if (imgLoader.LoadEPGImage(event->EventID())) {
        pixmapHeader->DrawImage(cPoint(width - config.epgImageWidth - border, (headerHeight-config.epgImageHeight)/2), imgLoader.GetImage());
        if (config.roundedCorners) {
            int radius = config.cornerRadius;
            int x = width - config.epgImageWidth - border;
            int y = (headerHeight-config.epgImageHeight)/2;
            pixmapHeader->DrawEllipse(cRect(x,y,radius,radius), clrTransparent, -2);
            pixmapHeader->DrawEllipse(cRect(x + config.epgImageWidth - radius,y,radius,radius), clrTransparent, -1);
            pixmapHeader->DrawEllipse(cRect(x,y + config.epgImageHeight - radius,radius,radius), clrTransparent, -3);
            pixmapHeader->DrawEllipse(cRect(x + config.epgImageWidth - radius,y + config.epgImageHeight - radius,radius,radius), clrTransparent, -4);
        }
        widthTextHeader -= config.epgImageWidth;
    }

    int lineHeight = fontHeaderLarge->Height();

    cString dateTime = cString::sprintf("%s  %s - %s", *event->GetDateString(), *event->GetTimeString(), *event->GetEndTimeString());
    pixmapHeader->DrawText(cPoint(logoWidth + 2*border, (lineHeight - fontHeader->Height())/2), *dateTime, Theme.Color(clrMenuFontDetailViewHeader), clrTransparent, fontHeader);

    cTextWrapper title;
    title.Set(event->Title(), fontHeaderLarge, widthTextHeader);
    int currentLineHeight = lineHeight;
    for (int i=0; i < title.Lines(); i++) {
        pixmapHeader->DrawText(cPoint(logoWidth + 2*border, currentLineHeight), title.GetLine(i), Theme.Color(clrMenuFontDetailViewHeaderTitle), clrTransparent, fontHeaderLarge);
        currentLineHeight += lineHeight;
    }

    cTextWrapper shortText;
    shortText.Set(event->ShortText(), fontHeader, widthTextHeader);
    currentLineHeight += (lineHeight - fontHeader->Height())/2;
    for (int i=0; i < shortText.Lines(); i++) {
        if ((currentLineHeight + fontHeader->Height()) < headerHeight) {
            pixmapHeader->DrawText(cPoint(logoWidth + 2*border, currentLineHeight), shortText.GetLine(i), Theme.Color(clrMenuFontDetailViewHeader), clrTransparent, fontHeader);
            currentLineHeight += fontHeader->Height();
        } else
            break;
    }

}

void cNopacityMenuDetailEventView::LoadReruns(void) {
    cPlugin *epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
    if (epgSearchPlugin && !isempty(event->Title())) {
        std::stringstream sstrReruns;
        Epgsearch_searchresults_v1_0 data;
        std::string strQuery = event->Title();
        if (config.useSubtitleRerun > 0) {
            if (config.useSubtitleRerun == 2 || !isempty(event->ShortText()))
                strQuery += "~";
            if (!isempty(event->ShortText()))
                strQuery += event->ShortText();
                data.useSubTitle = true;
        } else {
            data.useSubTitle = false;
        }
        data.query = (char *)strQuery.c_str();
        data.mode = 0;
        data.channelNr = 0;
        data.useTitle = true;
        data.useDescription = false;
        
        if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
            cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
            if (list && (list->Count() > 1)) {
                sstrReruns << tr("RERUNS OF THIS SHOW") << ':' << std::endl;
                int i = 0;
                for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r && i < config.numReruns; r = list->Next(r)) {
                    if ((event->ChannelID() == r->event->ChannelID()) && (event->StartTime() == r->event->StartTime()))
                        continue;
                    i++;
                    sstrReruns  << "- "
                                << *DayDateTime(r->event->StartTime());
                    cChannel *channel = Channels.GetByChannelID(r->event->ChannelID(), true, true);
                    if (channel)
                        sstrReruns << " " << channel->ShortName(true);
                    sstrReruns << ":  " << r->event->Title();
                    if (!isempty(r->event->ShortText()))
                        sstrReruns << "~" << r->event->ShortText();
                    sstrReruns << std::endl;
                }
                delete list;
            }
        }
        reruns.Set(sstrReruns.str().c_str(), font, width - 4 * border);
    }
}

void cNopacityMenuDetailEventView::DrawEPGPictures(int height) {
    int picsPerLine = width / (config.epgImageWidthLarge + border);
    int currentX = border;
    int currentY = height + border;
    int currentPicsPerLine = 1;
    cImageLoader imgLoader;
    for (int i=1; i <= numEPGPics; i++) {
        cString epgimage = cString::sprintf("%d_%d", event->EventID(), i);
        if (imgLoader.LoadAdditionalEPGImage(epgimage)) {
            pixmapContent->DrawImage(cPoint(currentX, currentY), imgLoader.GetImage());
            if (config.roundedCorners) {
                int radius = config.cornerRadius;
                pixmapContent->DrawEllipse(cRect(currentX,currentY,radius,radius), clrTransparent, -2);
                pixmapContent->DrawEllipse(cRect(currentX + config.epgImageWidthLarge - radius,currentY,radius,radius), clrTransparent, -1);
                pixmapContent->DrawEllipse(cRect(currentX,currentY + config.epgImageHeightLarge - radius,radius,radius), clrTransparent, -3);
                pixmapContent->DrawEllipse(cRect(currentX + config.epgImageWidthLarge - radius,currentY + config.epgImageHeightLarge - radius,radius,radius), clrTransparent, -4);
            }
            if (currentPicsPerLine < picsPerLine) {
                currentX += config.epgImageWidthLarge + border;
                currentPicsPerLine++;
            } else {
                currentX = border;
                currentY += config.epgImageHeightLarge + border;
                currentPicsPerLine = 1;
            }
        } else {
            break;
        }
    }
}

//------------------cNopacityMenuDetailRecordingView------------------

cNopacityMenuDetailRecordingView::cNopacityMenuDetailRecordingView(cOsd *osd, const cRecording *Recording) : cNopacityMenuDetailView(osd) {
    recording = Recording;
    info = Recording->Info();
}

cNopacityMenuDetailRecordingView::~cNopacityMenuDetailRecordingView(void) {
    osd->DestroyPixmap(pixmapHeader);
    osd->DestroyPixmap(pixmapContent);
}

void cNopacityMenuDetailRecordingView::CreatePixmaps(void) {
    pixmapHeader =  osd->CreatePixmap(3, cRect(x, top, width, headerHeight));
    pixmapContent = osd->CreatePixmap(3, cRect(x, top + headerHeight, width, contentHeight),
                                         cRect(0, 0, width, contentDrawPortHeight));

    pixmapHeader->Fill(clrTransparent);
    pixmapHeader->DrawRectangle(cRect(0, headerHeight - 2, width, 2), Theme.Color(clrMenuBorder));
    pixmapContent->Fill(clrTransparent);
}

void cNopacityMenuDetailRecordingView::SetFonts(void) {
    font = cFont::CreateFont(config.fontName, contentHeight / 25 + config.fontDetailView);
    fontHeaderLarge = cFont::CreateFont(config.fontName, headerHeight / 4 + config.fontDetailViewHeaderLarge);
    fontHeader = cFont::CreateFont(config.fontName, headerHeight / 6 + config.fontDetailViewHeader);
}

void cNopacityMenuDetailRecordingView::SetContent(void) {
    if (recording) {
        content.Set(recording->Info()->Description(), font, width - 4 * border);
        LoadRecordingInformation();
    }   
}

void cNopacityMenuDetailRecordingView::SetContentHeight(void) {
    int lineHeight = font->Height();
    int linesContent = content.Lines() + 1;
    linesContent+= additionalInfo.Lines() + 1;
    int heightContentText = linesContent * lineHeight;
    if (config.displayAdditionalRecEPGPictures) {
        if (LoadEPGPics())
            heightContentText += HeightEPGPics();
    }
    if (heightContentText > contentHeight) {
        contentDrawPortHeight = heightContentText;
        hasScrollbar = true;
    } else {
        contentDrawPortHeight = contentHeight;  
    }
}

bool cNopacityMenuDetailRecordingView::LoadEPGPics(void) {
    DIR *dirHandle;
    struct dirent *dirEntry;
    dirHandle = opendir(recording->FileName());
    int picsFound = 0;
    if (dirHandle != NULL) {
        while ( 0 != (dirEntry = readdir(dirHandle))) {
            if (endswith(dirEntry->d_name, "jpg")) { 
                std::string fileName = dirEntry->d_name;
                if (fileName.length() > 4) {
                    fileName = fileName.substr(0, fileName.length() - 4);
                    epgpics.push_back(fileName);
                    picsFound++;
                }
            }
            if (picsFound >= config.numAdditionalRecEPGPictures)
                break;
        }
        closedir(dirHandle);
    }
    if (picsFound > 0)
        return true;
    return false;
}

int cNopacityMenuDetailRecordingView::HeightEPGPics(void) {
    int numPicsAvailable = epgpics.size();
    int picsPerLine = width / (config.epgImageWidthLarge + border);
    int picLines = numPicsAvailable / picsPerLine;
    if (numPicsAvailable%picsPerLine != 0)
        picLines++;
    return picLines * (config.epgImageHeightLarge + border) + 2*border;
}

void cNopacityMenuDetailRecordingView::DrawEPGPictures(int height) {
    int picsPerLine = width / (config.epgImageWidthLarge + border);
    int currentX = border;
    int currentY = height + border;
    int currentPicsPerLine = 1;
    cImageLoader imgLoader;
    for (unsigned i=0; i < epgpics.size(); i++) {
        cString path = cString::sprintf("%s/", recording->FileName());
        cString epgimage = epgpics.at(i).c_str();
        if (imgLoader.LoadAdditionalRecordingImage(path, epgimage)) {
            pixmapContent->DrawImage(cPoint(currentX, currentY), imgLoader.GetImage());
            if (config.roundedCorners) {
                int radius = config.cornerRadius;
                pixmapContent->DrawEllipse(cRect(currentX,currentY,radius,radius), clrTransparent, -2);
                pixmapContent->DrawEllipse(cRect(currentX + config.epgImageWidthLarge - radius,currentY,radius,radius), clrTransparent, -1);
                pixmapContent->DrawEllipse(cRect(currentX,currentY + config.epgImageHeightLarge - radius,radius,radius), clrTransparent, -3);
                pixmapContent->DrawEllipse(cRect(currentX + config.epgImageWidthLarge - radius,currentY + config.epgImageHeightLarge - radius,radius,radius), clrTransparent, -4);
            }
            if (currentPicsPerLine < picsPerLine) {
                currentX += config.epgImageWidthLarge + border;
                currentPicsPerLine++;
            } else {
                currentX = border;
                currentY += config.epgImageHeightLarge + border;
                currentPicsPerLine = 1;
            }
        } else {
            break;
        }
    }
}

void cNopacityMenuDetailRecordingView::Render(void) {
    DrawHeader();
    int currentHeight = DrawTextWrapper(&content, 0);
    currentHeight = DrawTextWrapper(&additionalInfo, currentHeight);
    if (epgpics.size() > 0) {
        DrawEPGPictures(currentHeight);
    }
}

void cNopacityMenuDetailRecordingView::DrawHeader(void) {
    cImageLoader imgLoader;
	int widthTextHeader = width - 4 * border;
    if (imgLoader.LoadRecordingImage(recording->FileName())) {
        pixmapHeader->DrawImage(cPoint(width - config.epgImageWidth - border, (headerHeight-config.epgImageHeight)/2), imgLoader.GetImage());
        if (config.roundedCorners) {
            int radius = config.cornerRadius;
            int x = width - config.epgImageWidth - border;
            int y = (headerHeight-config.epgImageHeight)/2;
            pixmapHeader->DrawEllipse(cRect(x,y,radius,radius), clrTransparent, -2);
            pixmapHeader->DrawEllipse(cRect(x + config.epgImageWidth - radius,y,radius,radius), clrTransparent, -1);
            pixmapHeader->DrawEllipse(cRect(x,y + config.epgImageHeight - radius,radius,radius), clrTransparent, -3);
            pixmapHeader->DrawEllipse(cRect(x + config.epgImageWidth - radius,y + config.epgImageHeight - radius,radius,radius), clrTransparent, -4);
        }
        widthTextHeader -= config.epgImageWidth;
    }
    int lineHeight = fontHeaderLarge->Height();
    cString dateTime = cString::sprintf("%s  %s", *DateString(recording->Start()), *TimeString(recording->Start()));
	pixmapHeader->DrawText(cPoint(2*border, (lineHeight - fontHeader->Height())/2), *dateTime, Theme.Color(clrMenuFontDetailViewHeader), clrTransparent, fontHeader);
    
    const char *Title = info->Title();
    if (isempty(Title))
        Title = recording->Name();
	cTextWrapper title;
	title.Set(Title, fontHeaderLarge, widthTextHeader);
    int currentLineHeight = lineHeight;
	for (int i=0; i < title.Lines(); i++) {
        pixmapHeader->DrawText(cPoint(2*border, currentLineHeight), title.GetLine(i), Theme.Color(clrMenuFontDetailViewHeaderTitle), clrTransparent, fontHeaderLarge);
        currentLineHeight += lineHeight;
    }
	
    if (!isempty(info->ShortText())) {
        cTextWrapper shortText;
        shortText.Set(info->ShortText(), fontHeader, widthTextHeader);
        for (int i=0; i < shortText.Lines(); i++) {
            if ((currentLineHeight + fontHeader->Height()) < headerHeight) {
                pixmapHeader->DrawText(cPoint(2*border, currentLineHeight), shortText.GetLine(i), Theme.Color(clrMenuFontDetailViewHeader), clrTransparent, fontHeader);
                currentLineHeight += fontHeader->Height();
        } else
            break;
        }
    }
}

void cNopacityMenuDetailRecordingView::LoadRecordingInformation(void) {
    const cRecordingInfo *Info = recording->Info();
    unsigned long long nRecSize = -1;
    unsigned long long nFileSize[1000];
    nFileSize[0] = 0;
    int i = 0;
    struct stat filebuf;
    cString filename;
    int rc = 0;
    do {
        if (recording->IsPesRecording())
            filename = cString::sprintf("%s/%03d.vdr", recording->FileName(), ++i);
        else
            filename = cString::sprintf("%s/%05d.ts", recording->FileName(), ++i);
        rc = stat(filename, &filebuf);
        if (rc == 0)
            nFileSize[i] = nFileSize[i-1] + filebuf.st_size;
        else
            if (ENOENT != errno) {
                nRecSize = -1;
            }
    } while (i <= 999 && !rc);
    nRecSize = nFileSize[i-1];

    cMarks marks;
    bool fHasMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count();
    cIndexFile *index = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());

    int nCutLength = 0;
    long nCutInFrame = 0;
    unsigned long long nRecSizeCut = nRecSize < 0 ? -1 : 0;
    unsigned long long nCutInOffset = 0;

    if (fHasMarks && index) {
        uint16_t FileNumber;
        off_t FileOffset;

        bool fCutIn = true;
        cMark *mark = marks.First();
        while (mark) {
            int pos = mark->Position();
            index->Get(pos, &FileNumber, &FileOffset); //TODO: will disc spin up?
            if (fCutIn) {
                nCutInFrame = pos;
                fCutIn = false;
                if (nRecSize >= 0)
                    nCutInOffset = nFileSize[FileNumber-1] + FileOffset;
            } else {
                nCutLength += pos - nCutInFrame;
                fCutIn = true;
                if (nRecSize >= 0)
                    nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
            }
            cMark *nextmark = marks.Next(mark);
            mark = nextmark;
        }
        if (!fCutIn) {
            nCutLength += index->Last() - nCutInFrame;
            index->Get(index->Last() - 1, &FileNumber, &FileOffset);
            if (nRecSize >= 0)
                nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
        }
    }

    std::stringstream sstrInfo;

    cChannel *channel = Channels.GetByChannelID(Info->ChannelID());
    if (channel)
        sstrInfo << trVDR("Channel") << ": " << channel->Number() << " - " << channel->Name() << std::endl;
    if (nRecSize < 0) {
        if ((nRecSize = ReadSizeVdr(recording->FileName())) < 0) {
            nRecSize = DirSizeMB(recording->FileName());
        }
    }
    if (nRecSize >= 0) {
        cString strRecSize = "";
        if (fHasMarks) {
            if (nRecSize > MEGABYTE(1023))
                strRecSize = cString::sprintf("%s: %.2f GB (%s: %.2f GB)", tr("Size"), (float)nRecSize / MEGABYTE(1024), tr("cut"), (float)nRecSizeCut / MEGABYTE(1024));
            else
                strRecSize = cString::sprintf("%s: %lld MB (%s: %lld MB)", tr("Size"), nRecSize / MEGABYTE(1), tr("cut"), nRecSizeCut / MEGABYTE(1));
        } else {
            if (nRecSize > MEGABYTE(1023))
                strRecSize = cString::sprintf("%s: %.2f GB", tr("Size"), (float)nRecSize / MEGABYTE(1024));
            else
                strRecSize = cString::sprintf("%s: %lld MB", tr("Size"), nRecSize / MEGABYTE(1));
        }
        sstrInfo << (const char*)strRecSize << std::endl;
    }
    
    if (index) {
        int nLastIndex = index->Last();
        if (nLastIndex) {
            cString strLength;
            if (fHasMarks) {
                strLength = cString::sprintf("%s: %s (%s %s)", tr("Length"), *IndexToHMSF(nLastIndex, false, recording->FramesPerSecond()), tr("cut"), *IndexToHMSF(nCutLength, false, recording->FramesPerSecond()));
            } else {
                strLength = cString::sprintf("%s: %s", tr("Length"), *IndexToHMSF(nLastIndex, false, recording->FramesPerSecond()));
            }
            sstrInfo << (const char*)strLength << std::endl;
            cString strBitrate = cString::sprintf("%s: %s\n%s: %.2f MBit/s (Video+Audio)", tr("Format"), recording->IsPesRecording() ? "PES" : "TS", tr("Est. bitrate"), (float)nRecSize / nLastIndex * recording->FramesPerSecond() * 8 / MEGABYTE(1));
            sstrInfo << (const char*)strBitrate << std::endl;
        }
    }
    delete index;
    
    additionalInfo.Set(sstrInfo.str().c_str(), font, width - 4 * border);
}

int cNopacityMenuDetailRecordingView::ReadSizeVdr(const char *strPath) {
    int dirSize = -1;
    char buffer[20];
    char *strFilename = NULL;
    if (-1 != asprintf(&strFilename, "%s/size.vdr", strPath)) {
        struct stat st;
        if (stat(strFilename, &st) == 0) {
                int fd = open(strFilename, O_RDONLY);
            if (fd >= 0) {
                if (safe_read(fd, &buffer, sizeof(buffer)) >= 0) {
                    dirSize = atoi(buffer);
                }
                close(fd);
            }
        }
        free(strFilename);
    }
    return dirSize;
}

//---------------cNopacityMenuDetailTextView---------------------

cNopacityMenuDetailTextView::cNopacityMenuDetailTextView(cOsd *osd, const char *text) : cNopacityMenuDetailView(osd) {
    this->text = text;
}

cNopacityMenuDetailTextView::~cNopacityMenuDetailTextView(void) {
    osd->DestroyPixmap(pixmapContent);
}

void cNopacityMenuDetailTextView::SetFonts(void) {
    font = cFont::CreateFont(config.fontName, contentHeight / 25 + config.fontDetailView);
    fontHeaderLarge = NULL;
    fontHeader = NULL;
}

void cNopacityMenuDetailTextView::SetContent(void) {
    content.Set(text, font, width - 4 * border);
}

void cNopacityMenuDetailTextView::SetContentHeight(void) {
    int lineHeight = font->Height();
    int linesContent = content.Lines() + 1;

    int heightContentText = linesContent * lineHeight;
    if (heightContentText > contentHeight) {
        contentDrawPortHeight = heightContentText;
        hasScrollbar = true;
    } else {
        contentDrawPortHeight = contentHeight;  
    }
}

void cNopacityMenuDetailTextView::CreatePixmaps(void) {
    pixmapContent = osd->CreatePixmap(3, cRect(x, top + headerHeight, width, contentHeight),
                                         cRect(0, 0, width, contentDrawPortHeight));

    pixmapContent->Fill(clrTransparent);
}

void cNopacityMenuDetailTextView::Render(void) {
    DrawTextWrapper(&content, 0);
}