#include "tester_cs.h"
#include "GridsView.h"
#include "NuuoGLRenderer.h"
#include <QDateTime>
#include <QFileDialog>
#ifndef WIN32
#include <sys/time.h>
#endif

static Np_ServerType checkServerType(QString type);
static bool isValidFilename(const QString &filename);
static QString getEventIDText(int ID);

static void VideoHandle(Np_DateTime time,
                        char* buffer, 
                        int len,
                        int width, 
                        int height, 
                        void* ctx)
{
    stSession* pst = static_cast<stSession *>(ctx);

    pst->width = width;
    pst->height = height;
    if (kPixelFormatYUV420P == pst->pInst->m_videoPixelFmt)
    {
        pst->pInst->m_pRender->OnImageArrival(width, height, width*height*3/2, (uchar*)buffer, 0);
    }
    else
    {
        pst->pInst->m_pRender->OnBGRArrival(width, height, width*3, (uchar*)buffer, 0);
    }
}

static void AudioHandle(Np_DateTime time,
                        char* buffer, 
                        int len, 
                        int bitsPerSample, 
                        int samplesPerSec, 
                        int channels, 
                        void* ctx)
{
#ifdef WIN32
    stSession* pst = static_cast<stSession *>(ctx);

    if(pst && pst->pInst->m_SoundDev)
    {
        pst->pInst->m_SoundDev->WriteSoundData((BYTE*)buffer, len, channels, bitsPerSample, samplesPerSec);
    }
#endif
}

static void ErrorHandle(Np_Error error, void* ctx)
{
    if (Np_ERROR_CONNECT_SUCCESS == error)
    {
        stSession* pst = static_cast<stSession *>(ctx);

        pst->pInst->SetPBFileOpen(true);
    }
}

static void EventHandle(Np_Event e, void* ctx)
{
    Tester* p = static_cast<Tester*>(ctx);   
    p->showText("===EventHandle===");
    p->showEvent(e);
    p->showText("==========");
}

static void ExportHandle(  Np_ID id, 
                           Np_ExportError error, 
                           unsigned int percent,
                           int iFormateChangedIndex,
                           void* ctx)
{
    stSession* pst = static_cast<stSession *>(ctx);
    if(pst != NULL)
    {
        pst->pInst->PutExportCbInfo(id, error, percent, iFormateChangedIndex);
    }
}

static void OSDHandle( Np_ID id,
                       char* buffer,
                       int width,
                       int height,
                       Np_DateTime time, 
                       void* ctx)
{
}

static QString FormatExportFilePath(QString basePath, int iFormatChangedIndex, QString formatDesc)
{
    QString path = basePath;
    if(iFormatChangedIndex > 0)
    {
        path.append(QString("_%1").arg(iFormatChangedIndex));
    }

    if(formatDesc.contains("ASF"))
    {
        path.append(".ASF");
    }
    if(formatDesc.contains("AVI"))
    {
        path.append(".AVI");
    }
    if(formatDesc.contains("MOV"))
    {
        path.append(".MOV");
    }

    return path;
}

Tester::Tester(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
    , m_handle(NULL)
    , m_eventsession(NULL)
    , m_lvplayer(NULL)    
    , m_pbplayer(NULL)    
    , m_pGridsView(new CGridsView(this))    
    , m_pRender(new NuuoGLRenderer(1))
    , m_videoPixelFmt(kPixelFormatYUV420P)
{
    ui.setupUi(this);   
    ui.LiveviewGridLayout->setSpacing(0);
    ui.LiveviewGridLayout->setMargin(0);
    ui.LiveviewGridLayout->addWidget(m_pGridsView);    
    m_pGridsView->AddWidget(m_pRender, 0, 0, 1, 1);  
    //////////////////////////////////////////////////////////////////////////
    // Setup timer
    m_FrameUpdateTimer.setInterval(1000/30);
    connect(&m_FrameUpdateTimer, SIGNAL(timeout()), this, SLOT(OnUpdateFrame()));
    m_FrameUpdateTimer.start();

    m_UpdateUItimer.setInterval(10);
    connect(&m_UpdateUItimer, SIGNAL(timeout()), this, SLOT(OnUpdateUI()));
    m_UpdateUItimer.start();
    SetPlaybackButtonStatus(false);
    m_bPBFileOpen = false;
    m_bExporting = false;

    AdjustTesterUI();

    memset(&m_deviceList, 0, sizeof(Np_DeviceList_CS));

#ifdef WIN32
    m_SoundDev = GetSoundDevice();
#endif
}

Tester::~Tester()
{
    if (m_handle != NULL)
    {
        if (m_lvplayer != NULL)
        {
            for (int i=0; i<m_lvsessions.size(); i++)
            {
                LiveView_DetachSession(m_lvplayer, m_lvsessions[i]->session);
                delete m_lvsessions[i];
            }
            LiveView_DestroyPlayer(m_lvplayer);
        }

        if (m_pbplayer != NULL)
        {
            if(m_bExporting)
            {
                PlayBack_StopExport(m_pbplayer);
            }

            for (int i=0; i<m_pbsessions.size(); i++)
            {
                PlayBack_DetachSession(m_pbplayer, m_pbsessions[i]->session);
                delete m_pbsessions[i];
            }
            PlayBack_DestroyPlayer(m_pbplayer);
        }
        Destroy_Handle(m_handle);
    }
}
void Tester::convertTime(QDateTime src, Np_DateTime& dst)
{
    dst.year = src.date().year();
    dst.month = src.date().month();
    dst.day = src.date().day();
    dst.hour = src.time().hour();
    dst.minute = src.time().minute();
    dst.second = src.time().second();
    dst.millisecond = src.time().msec();
}

void Tester::showText(QString text)
{
    ui.textEdit->append(text);
}

void Tester::showResult(Np_Result_t result)                        
{
    switch(result)
    {
    case Np_Result_OK:
        showText("OK");
        break;
    case Np_Result_CLI_FAULT:
        showText("CLI_FAULT");
        break;
    case Np_Result_SVR_FAULT:
        showText("SVR_FAULT");
        break;
    case Np_Result_USER_ERROR:
        showText("USER_ERROR");
        break;
    case Np_Result_FAILED:
        showText("FAILED");
        break;
    case Np_Result_NO_METHOD:
        showText("NO_METHOD");
        break;
    case Np_Result_NO_DATA:
        showText("NO_DATA");
        break;
    case Np_Result_SOCKET_ERROR:
        showText("SOCKET_ERROR");
        break;
    case Np_Result_INVALID_ARGUMENT:
        showText("INVALID_ARGUMENT");
        break;
    case Np_Result_FATAL_ERROR:
        showText("FATAL_ERROR");
        break;
    default:
        showText("Np_Result is Unrecognizable !!!");
        break;
    }
    showText("\n");
}

void Tester::showTime(QString title, Np_DateTime time)
{
    showText(title);
    QString str;
    str = QString(
        "year = %1\n"
        "month = %2\n"
        "day = %3\n"
        "hour = %4\n"
        "minute = %5\n"
        "second = %6\n"
        "millisecond = %7"
        )
        .arg(time.year)
        .arg(time.month)
        .arg(time.day)
        .arg(time.hour)
        .arg(time.minute)
        .arg(time.second)    
        .arg(time.millisecond);
    showText(str);
    showText("\n");
}

void Tester::showCfgLog(Np_ConfigurationLog_CS log)
{
    showID("Event Source ID",log.sourceID);
    showTime("event occurTime",log.occurTime);
    showText(getEventIDText(log.eventID));
    showText("\n");
}
void Tester::showOpLog(Np_OperationLog_CS log)
{
    showID("Event Source ID",log.sourceID);
    showTime("event occurTime",log.occurTime);
    showText(getEventIDText(log.eventID));
    showText("\n");
}
void Tester::showLog(Np_Log_CS log)
{
    int i = 0;
    showText("ConfigurationLog:\n");
    for (i = 0; i < log.cnfgLog.size; ++i ) 
        showCfgLog(log.cnfgLog.items[i]);   
    showText("OperationLog:\n");
    for (i = 0; i < log.opLog.size; ++i ) 
        showOpLog(log.opLog.items[i]);    
}
void Tester::showRecordDateList(Np_RecordDateList dateList)
{
    if (0 == dateList.size)
    {
        showText("No Dates have Record Logs");
        return;
    }

    for (int i=0; i<dateList.size; i++)
    {
        showTime("Record date", dateList.dateList[i]);
    }
}
void Tester::showRecordLogItem(Np_RecordLogItem logItem)
{
    showText("---Record Log---\n");
    showID("Device ID",logItem.ID);
    showTime("Reocord StartTime",logItem.startTime);
    showTime("Reocord EndTime",logItem.endTime);
}
void Tester::showRecordLogs(Np_RecordLogList logList)
{
    if (0 == logList.size)
    {
        showText("No Record Logs");
        return;
    }

    for (int i=0; i<logList.size; i++)
    {
        showRecordLogItem(logList.logList[i]);
    }
}
void Tester::showSchduleType(Np_ScheduleType schType)
{
    showText("Schedule Type:");
    switch(schType)
    {
        case kScheduleNone:
        {
            showText("kScheduleNone");
            break;
        }
        case kScheduleRecordOnly:
        {
            showText("kScheduleRecordOnly");
            break;
        }
        case kScheduleMotionDetectOnly:
        {
            showText("kScheduleMotionDetectOnly");
            break;
        }
        case kScheduleRecordAndMotionDetect:
        {
            showText("kScheduleRecordAndMotionDetect");
            break;
        }
        case kScheduleRecordMovingOnly:
        {
            showText("kScheduleRecordMovingOnly");
            break;
        }
        case kScheduleRecordOnEvent:
        {
            showText("kScheduleRecordOnEvent");
            break;
        }
        case kScheduleUndefined:
        {
            showText("kScheduleUndefined");
            break;
        }
        case kScheduleRecordBoost:
        {
            showText("kScheduleRecordBoost");
            break;
        }
        default:
        {
            showText("Schedule Type is Unrecognizable !!!");
            break;
        }
    }
    showText("\n");
}
void Tester::showScheduleLogItem(Np_ScheduleLogItem logItem)
{
    showText("---Scheudle Log---\n");
    showID("Device ID",logItem.ID);
    showSchduleType(logItem.type);
    showTime("Scheudle StartTime",logItem.startTime);
    showTime("Scheudle EndTime",logItem.endTime);
}
void Tester::showScheduleLogs(Np_ScheduleLogList logList)
{
    if (0 == logList.size)
    {
        showText("No Schedule Logs");
        return;
    }

    for (int i=0; i<logList.size; i++)
    {
        showScheduleLogItem(logList.logList[i]);
    }
}
void Tester::showEvent(Np_Event event)
{
    QString description = QString("Description: %1\n").arg(QString::fromWCharArray(event.description));
    QString eventID = getEventIDText(event.eventID);
    if(eventID.size() == 0)
    {
        return; //Ignore unrecognizable events
    }
    showID("Event Source ID",event.sourceID);
    showTime("event occurTime",event.occurTime);
    showText(eventID);
    showText("\n");
    showText(description);
}
void Tester::showEventList(Np_EventList eventList)
{
    if (0 == eventList.size)
    {
        showText("No Events");
        return;
    }

    for (int i=0; i<eventList.size; i++)
    {
        showEvent(eventList.list[i]);
    }
}
void Tester::showID(QString title,Np_ID ID)
{
    showText(title);
    QString str = QString("central ID: %1\n"
                          "local ID: %2\n").
                          arg(ID.centralID).
                          arg(ID.localID);
    showText(str);
}
void Tester::showWString(QString title,std::wstring str)
{
    QString qstr;   
    showText(title);
    qstr = QString::fromStdWString(str);
    showText(qstr);
    //showText("\n");
}
void Tester::showSubDevice(Np_SubDevice_CS device)
{
    showID("SubDeviceID",device.ID);
    showWString("Device Name:",device.name); 
    showWString("Device Description:",device.description); 
}
void Tester::showDevice(Np_Device_CS device)
{     
    showID("==========DeviceID",device.ID);
    showWString("Device Name:",device.name); 
    showWString("Device Description:",device.description); 
    
    int i = 0;
    showText("Sensor Device:\n");
    for (i = 0; i < device.SensorDevices.size; ++i ) 
        showSubDevice(device.SensorDevices.items[i]);   
    showText("PTZ Device:\n");
    for (i = 0; i < device.PTZDevices.size; ++i )
    {
        showSubDevice(device.PTZDevices.items[i]);
        showPTZCapability(device.PTZDevices.items[i]);
    }
    showText("DI Device:\n");
    for (i = 0; i < device.DIDevices.size; ++i ) 
        showSubDevice(device.DIDevices.items[i]);
    showText("DO Device:\n");
    for (i = 0; i < device.DODevices.size; ++i ) 
        showSubDevice(device.DODevices.items[i]);
    showText("Audio Device:\n");
    for (i = 0; i < device.AudioDevices.size; ++i ) 
        showSubDevice(device.AudioDevices.items[i]);   
}
void Tester::showDeviceGroup(Np_DeviceGroup_CS group)
{    
    showWString("Group(Server) Name:",group.name); 
    showWString("Group(Server) Description:",group.description); 
    int i = 0;
    showText("=====Cameras:\n");
    for (i = 0; i < group.Camera.size; ++i ) 
        showDevice(group.Camera.items[i]);   
    showText("=====IOBox:\n");
    for (i = 0; i < group.IOBox.size; ++i ) 
        showDevice(group.IOBox.items[i]);   
}
void Tester::showDeviceList(Np_DeviceList_CS list)
{
    int i = 0;
    showText("Logical Group:\n");
    for (i = 0; i < list.LogicalGroup.size; ++i ) 
        showDeviceGroup(list.LogicalGroup.items[i]);   
    showText("Physical Group:\n");
    for (i = 0; i < list.PhysicalGroup.size; ++i ) 
        showDeviceGroup(list.PhysicalGroup.items[i]);        
}

void Tester::showStreamProfile(Np_StreamProfile streamProfile)
{
    switch(streamProfile)
    {
        case kProfileNormal:
        {
            showText("kProfileNormal");
            break;
        }
        case kProfileOriginal:
        {
            showText("kProfileOriginal");
            break;
        }
        case kProfileLow:
        {
            showText("kProfileLow");
            break;
        }
        case kProfileMinimum:
        {
            showText("kProfileMinimum");
            break;
        }
        default:
        {
            showText("Stream Profile is Unrecognizable !!!");
            break;
        }
    }
}

void Tester::showSensorProfile(Np_SensorProfile_CS sensorProfile)
{
    showStreamProfile(sensorProfile.profile);
    showText(QString("Bitrate: %1").arg(QString::fromStdWString(sensorProfile.bitrate)));
    showText(QString("Codec: %1").arg(QString::fromStdWString(sensorProfile.codec)));
    showText(QString("FrameRate: %1").arg(QString::fromStdWString(sensorProfile.frameRate)));
    showText(QString("Quality: %1").arg(QString::fromStdWString(sensorProfile.quality)));
    showText(QString("Resolution: %1").arg(QString::fromStdWString(sensorProfile.resolution)));
    showText("----------\n");
}

void Tester::showSensorProfileList(Np_SensorProfile_CS_List sensorProfileList)
{
    for (int i = 0; i < sensorProfileList.size; ++i ) 
        showSensorProfile(sensorProfileList.items[i]);   
}

void Tester::showPTZCapability(Np_SubDevice_CS device)
{
        Np_Result_t ret = Np_Result_OK;
        long long ptzCap = 0;
        ret = Info_GetPTZCapability(m_handle, device.ID, ptzCap);
        if(ret == Np_Result_OK)
        {
            QString szCapability = "PTZ capability supported:\r\n";
            if(ptzCap & kPTZAreaZoom)
                szCapability += "    Area Zoom\r\n";
            if(ptzCap & kPTZAutoPan)
                szCapability += "    Auto Pan\r\n";
            if(ptzCap & kPTZFocus)
                szCapability += "    Focus\r\n";
            if(ptzCap & kPTZLilin)
                szCapability += "    Lilin\r\n";
            if(ptzCap & kPTZPane)
                szCapability += "    Pane\r\n";
            if(ptzCap & kPTZPreset)
                szCapability += "    Preset\r\n";
            if(ptzCap & kPTZSpeedDomeOSDMenu)
                szCapability += "    Speed Dome OSD Menu\r\n";
            if(ptzCap & kPTZTilt)
                szCapability += "    Tilt\r\n";
            if(ptzCap & kPTZZoom)
                szCapability += "    Zoom\r\n";
            showText(szCapability);
        }
}

void Tester::showPTZPreset(Np_PTZPreset_CS ptzPreset)
{
    showText("=====PresetInfo\n");
    showText(QString("PresetName: %1").arg(QString::fromStdWString(ptzPreset.presetName))); 
    showText(QString("PresetNo: %1").arg(ptzPreset.presetNo));
    showText("\n");
}

void Tester::showPTZPresetList(Np_PTZPreset_CS_List ptzPresetList)
{
    for (int i = 0; i < ptzPresetList.size; ++i ) 
        showPTZPreset(ptzPresetList.items[i]);  
}

static Np_ServerType checkServerType(QString type)
{
    if(!type.compare("MainConsoleLiveview"))
        return kMainConsoleLiveview;
    if(!type.compare("MainConsolePlayback"))
        return kMainConsolePlayback;
    if(!type.compare("Corporate"))
        return kCorporate;
    if(!type.compare("Titan"))
        return kTitan;
    Q_ASSERT(0);    
    exit(1);
    return kCorporate;
}

static int checkEventID(QString id)
{
    if(!id.compare("ALL"))
    {
        return Np_EVENT_CODE_BASE;
    }
    if(!id.compare("Np_EVENT_MOTION_1"))
    {
        return Np_EVENT_GENERAL_MOTION_1;
    }
    if(!id.compare("Np_EVENT_MOTION_2"))
    {
        return Np_EVENT_GENERAL_MOTION_2;
    }
    if(!id.compare("Np_EVENT_MOTION_3"))
    {
        return Np_EVENT_GENERAL_MOTION_3;
    }
    if(!id.compare("Np_EVENT_MOTION_4"))
    {
        return Np_EVENT_GENERAL_MOTION_4;
    }
    if(!id.compare("Np_EVENT_MOTION_5"))
    {
        return Np_EVENT_GENERAL_MOTION_5;
    }
    if(!id.compare("Np_EVENT_FOREIGN_OBJECT"))
    {
        return Np_EVENT_FOREIGN_OBJECT;
    }
    if(!id.compare("Np_EVENT_MISSING_OBJECT"))
    {
        return Np_EVENT_MISSING_OBJECT;
    }
    if(!id.compare("Np_EVENT_FOCUS_LOST"))
    {
        return Np_EVENT_FOCUS_LOST;
    }
    if(!id.compare("Np_EVENT_CAMERA_OCCLUSION"))
    {
        return Np_EVENT_CAMERA_OCCLUSION;
    }
    if(!id.compare("Np_EVENT_GENERAL_MOTION_DEVICE"))
    {
        return Np_EVENT_GENERAL_MOTION_DEVICE;
    }
    if(!id.compare("Np_EVENT_SIGNAL_LOST"))
    {
        return Np_EVENT_SIGNAL_LOST;
    }
    if(!id.compare("Np_EVENT_MOTION_START"))
    {
        return Np_EVENT_MOTION_START;
    }
    if(!id.compare("Np_EVENT_MOTION_STOP"))
    {
        return Np_EVENT_MOTION_STOP;
    }
    if(!id.compare("Np_EVENT_CONNECTION_LOST"))
    {
        return Np_EVENT_CONNECTION_LOST;
    }
    if(!id.compare("Np_EVENT_MANUAL_RECORD_MODE_START"))
    {
        return Np_EVENT_MANUAL_RECORD_MODE_START;
    }
    if(!id.compare("Np_EVENT_MANUAL_RECORD_MODE_STOP"))
    {
        return Np_EVENT_MANUAL_RECORD_MODE_STOP;
    }
    if(!id.compare("Np_EVENT_INPUT_OPENED"))
    {
        return Np_EVENT_INPUT_OPENED;
    }
    if(!id.compare("Np_EVENT_INPUT_CLOSED"))
    {
        return Np_EVENT_INPUT_CLOSED;
    }
    Q_ASSERT(0);    
    exit(1);
    return Np_EVENT_CODE_BASE;
}

static QString getEventIDText(int ID)
{
    switch(ID)
    {
        //------sensor
    case Np_EVENT_GENERAL_MOTION_1:
        return QString("Np_EVENT_MOTION_1");
        break;
    case Np_EVENT_GENERAL_MOTION_2:
        return QString("Np_EVENT_MOTION_2");
        break;
    case Np_EVENT_GENERAL_MOTION_3:
        return QString("Np_EVENT_MOTION_3");
        break;
    case Np_EVENT_GENERAL_MOTION_4:
        return QString("Np_EVENT_MOTION_4");
        break;
    case Np_EVENT_GENERAL_MOTION_5:
        return QString("Np_EVENT_MOTION_5");
        break;
    case Np_EVENT_FOREIGN_OBJECT:
        return QString("Np_EVENT_FOREIGN_OBJECT");
        break;
    case Np_EVENT_MISSING_OBJECT:
        return QString("Np_EVENT_MISSING_OBJECT");
        break;
    case Np_EVENT_FOCUS_LOST:
        return QString("Np_EVENT_FOCUS_LOST");
        break;
    case Np_EVENT_CAMERA_OCCLUSION:
        return QString("Np_EVENT_CAMERA_OCCLUSION");
        break;
    case Np_EVENT_GENERAL_MOTION_DEVICE:
        return QString("Np_EVENT_GENERAL_MOTION_DEVICE");
        break;
    case Np_EVENT_SIGNAL_LOST:
        return QString("Np_EVENT_SIGNAL_LOST");
        break;
    case Np_EVENT_MOTION_START:
        return QString("Np_EVENT_MOTION_START");
        break;
    case Np_EVENT_MOTION_STOP:
        return QString("Np_EVENT_MOTION_STOP");
        break;
    case Np_EVENT_CONNECTION_LOST:
        return QString("Np_EVENT_CONNECTION_LOST");
        break;
    case Np_EVENT_MANUAL_RECORD_MODE_START:
        return QString("Np_EVENT_MANUAL_RECORD_MODE_START");
        break;
    case Np_EVENT_MANUAL_RECORD_MODE_STOP:
        return QString("Np_EVENT_MANUAL_RECORD_MODE_STOP");
        break;
    case Np_EVENT_INPUT_OPENED:
        return QString("Np_EVENT_INPUT_OPENED");
        break;
    case Np_EVENT_INPUT_CLOSED:
        return QString("Np_EVENT_INPUT_CLOSED");
        break;
    default:
        return QString("");
        break;
    }
}

static Np_StreamProfile checkStreamProfile(QString profile)
{
    if(!profile.compare("Normal"))
    {
        return kProfileNormal;
    }
    if(!profile.compare("Original"))
    {
        return kProfileOriginal;
    }
    if(!profile.compare("Low"))
    {
        return kProfileLow;
    }
    if(!profile.compare("Minimum"))
    {
        return kProfileMinimum;
    }
    Q_ASSERT(0);
    exit(1);
    return kProfileNormal;
}

static bool checkDOControl(QString id)
{
    if(!id.compare("TurnOn"))
    {
        return true;
    }
    if(!id.compare("TurnOff"))
    {
        return false;
    }
    Q_ASSERT(0);    
    exit(1);
    return true;
}

static bool isValidFilename(const QString& filename)
{
#ifdef WIN32
const char s_invalidChar[] = {'\\', '/', ':', '*', '?', '\"', '<', '>', '|'};
#else
const char s_invalidChar[] = {':', '/', '.'};
#endif

    for (int i = 0, size = sizeof(s_invalidChar) / sizeof(char); i < size; ++i)
    {
        if (filename.contains(s_invalidChar[i]))
        {
            return false;
        }
    }

    return filename.size() > 0;
}

void Tester::onCreateHandle()
{
    showText("***...CreateHandle...***");    
    Np_Result_t ret = Np_Result_OK;
    Np_ServerType type = checkServerType(ui.cbbServerType->currentText());
    ret = Create_HandleWChar(
        &m_handle,
        type,
        ui.leUsername->text().toStdWString().c_str(),
        ui.lePassword->text().toStdWString().c_str(),
        ui.leIPAddress->text().toStdWString().c_str(),
        ui.lePort->text().toUShort()
        );
    showResult(ret);

    if (Np_Result_OK == ret)
    {
        Info_GetDeviceList_CS(
            m_handle,
            m_deviceList
            );

        QStringList list;
        if(kMainConsolePlayback == type)
        {
            list.append("ALL");
            list.append("Np_EVENT_MOTION_1");
            list.append("Np_EVENT_MOTION_2");
            list.append("Np_EVENT_MOTION_3");
            list.append("Np_EVENT_MOTION_4");
            list.append("Np_EVENT_MOTION_5");
            list.append("Np_EVENT_FOREIGN_OBJECT");
            list.append("Np_EVENT_MISSING_OBJECT");
            list.append("Np_EVENT_FOCUS_LOST");
            list.append("Np_EVENT_CAMERA_OCCLUSION");
            list.append("Np_EVENT_GENERAL_MOTION_DEVICE");
            list.append("Np_EVENT_SIGNAL_LOST");
            ui.cbbPBEventID->setEnabled(true);
            ui.cbbPBEventID->clear();
            ui.cbbPBEventID->addItems(list);
        }
        else if(kCorporate == type)
        {
            list.append("ALL");
            list.append("Np_EVENT_MOTION_START");
            list.append("Np_EVENT_MOTION_STOP");
            list.append("Np_EVENT_CONNECTION_LOST");
            list.append("Np_EVENT_MANUAL_RECORD_MODE_START");
            list.append("Np_EVENT_MANUAL_RECORD_MODE_STOP");
            list.append("Np_EVENT_INPUT_OPENED");
            list.append("Np_EVENT_INPUT_CLOSED");
            ui.cbbPBEventID->setEnabled(true);
            ui.cbbPBEventID->clear();
            ui.cbbPBEventID->addItems(list);

            ui.btnPBGetScheduleLogs->setEnabled(false);
        }
    }
}
void Tester::onGetDeviceList()
 {
    showText("***...GetDeviceList...***");    
    Np_Result_t ret = Np_Result_OK;
    ret = Info_ReleaseDeviceList_CS(m_handle, m_deviceList);
    ret = Info_GetDeviceList_CS(
        m_handle,
        m_deviceList
        );
    showDeviceList(m_deviceList);
    showResult(ret);  
}
void Tester::onGetLog()
{
    showText("***...GetLog...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_LogConditions condition;
    condition.configurationLog = true;
    condition.operationLog = true;
    Np_Log_CS logs;
    ret = Info_GetLog_CS(
        m_handle,
        condition,
        logs
        );
    showLog(logs);
    showResult(ret);  
    Info_ReleaseLog_CS(m_handle, logs);
}

int getMonthDays(int year, int month)
{
    static const int month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    if(2 == month && 0 == year % 4)
    {
        return 29;
    }

    return month_days[month - 1];
}

void Tester::onGetRecordDateList()
{
    showText("***...GetRecordDateList...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_RecordDateList dateList;

    if(kCorporate == checkServerType(ui.cbbServerType->currentText()))
    {
        showText("Range applied : ");
        Np_DateTime start, end;
        QDateTime qDateTime = ui.pbDateEditQuery->dateTime();
        QDate qDate = qDateTime.date();
        qDateTime.setTime(QTime(0, 0));
        qDateTime.setDate(QDate(qDate.year(), qDate.month(), 1));
        convertTime(qDateTime, start);
        showTime("Start date", start);
        qDateTime.setDate(QDate(qDate.year(), qDate.month(), getMonthDays(qDate.year(), qDate.month())));
        convertTime(qDateTime, end);
        showTime("End date", end);
        ret = Info_GetRangedRecordDateList(
            m_handle,
            &start,
            &end,
            dateList
            );
        showText("==========\n");
    }
    else
    {
        ret = Info_GetRangedRecordDateList(
            m_handle,
            NULL,
            NULL,
            dateList
            );
    }
    if (Np_Result_OK == ret)
    {
        showRecordDateList(dateList);
        Info_ReleaseRecordDateList(m_handle, dateList);
    }
    showResult(ret);
}
void Tester::onGetRecordLogs()
{
    showText("***...GetRecordLogs...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_RecordLogList logList;
    Np_DateTime queryTime;    
    convertTime(ui.pbDateEditQuery->dateTime(),queryTime);
    ret = Info_GetRecordLogs(
        m_handle,
        queryTime,
        logList
        );
    if (Np_Result_OK == ret)
    {
        showRecordLogs(logList);
        Info_ReleaseRecordLogs(m_handle, logList);
    }
    showResult(ret);
}
void Tester::onGetScheduleLogs()
{
    showText("***...GetScheduleLogs...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_ScheduleLogList logList;
    Np_DateTime queryTime;    
    convertTime(ui.pbDateEditQuery->dateTime(),queryTime);
    ret = Info_GetScheduleLogs(
        m_handle,
        queryTime,
        logList
        );
    if (Np_Result_OK == ret)
    {
        showScheduleLogs(logList);
        Info_ReleaseScheduleLogs(m_handle, logList);
    }
    showResult(ret);
}
void Tester::onQueryEvents()
{
    showText("***...GetEventLogs...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_EventList eventList;
    Np_DateTime* fromTime = new Np_DateTime();
    Np_DateTime* toTime = new Np_DateTime();
    int* eventID = NULL;
    Np_ID* id = NULL;
    convertTime(ui.dateTimeEditFrom->dateTime(), *fromTime);
    convertTime(ui.dateTimeEditTo->dateTime(), *toTime);
    if (ui.dateTimeEditFrom->dateTime() > ui.dateTimeEditTo->dateTime())
    {
        showText("\n***...StartTime can't large than EndTime...***\n");
        return;
    }

    if (ui.lePBCentralID->text().compare("") && ui.lePBLocalID->text().compare("") )
    {
        id = new Np_ID();
        id->centralID = ui.lePBCentralID->text().toInt();
        id->localID = ui.lePBLocalID->text().toInt();
    }

    int tmp = checkEventID(ui.cbbPBEventID->currentText());
    if (Np_EVENT_CODE_BASE != tmp)
    {
        eventID = new int(tmp);
    }

    ret = Info_QueryEvents(
        m_handle,
        fromTime,
        toTime,
        NULL,
        id,
        eventID,
        eventList
        );

    if ( NULL != eventID)
    {
        delete eventID;
    }

    if ( NULL != id)
    {
        delete id;
    }

    delete fromTime;
    delete toTime;

    if (Np_Result_OK == ret)
    {
        showEventList(eventList);
        Info_ReleaseEvents(m_handle, eventList);
    }
    showResult(ret);
}
void Tester::onSubscribeEvent()
{
    showText("***...SubscribeEvent...***");    
    Np_Result_t ret = Np_Result_OK;    
    ret = Event_Subscribe(
        m_handle,
        &m_eventsession,
        EventHandle,
        this
        );
    showResult(ret);  
}
void Tester::onUnsubscribeEvent()
{
    showText("***...UnsubscribEvent...***");    
    Np_Result_t ret = Np_Result_OK;    
    ret = Event_Unsubscribe(        
        m_eventsession        
        );
    showResult(ret);  
}
void Tester::onDestroyHandle()
{
    showText("***...DestroyHandle...***");    
    Np_Result_t ret = Np_Result_OK;
    if(!m_handle)
        showText("handle is null...");

    ui.cbbPBEventID->setEnabled(false);

    Info_ReleaseDeviceList_CS(m_handle, m_deviceList);

    ret = Destroy_Handle(
        m_handle    
        );
    showResult(ret);
    m_handle = NULL;
    m_lvsessions.clear();
    m_pbsessions.clear();
    m_lvplayer = NULL;
    m_pbplayer = NULL;
}
void Tester::onTestGeneral()
{
    onCreateHandle();
    onGetDeviceList();
    onGetLog();
    onSubscribeEvent();
    onUnsubscribeEvent();
    onDestroyHandle();
}

void Yuv2Rgb(int width, int height, BYTE* buf, BYTE* RGBBuffer)
{
    BYTE *YBuffer = buf;
    BYTE *UBuffer = buf + height * width;
    BYTE *VBuffer = buf + (int)(height*width*1.25);
    int Yv, Uv, Vv, Rv, Gv, Bv;
    int writePos = 0;
    int i = 0, j = 0;
    int k = 0;
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            Yv = YBuffer[j]-16;
            k = (int)(j/2);
            Uv = UBuffer[k]-128;
            Vv = VBuffer[k]-128;
            Rv = ((298*Yv + 409*Vv + 128)>>8);
            Gv = ((298*Yv - 100*Uv - 208*Vv + 128)>>8);
            Bv = ((298*Yv + 516*Uv + 128)>>8);
            RGBBuffer[writePos++] = (Bv < 0) ? 0 : ((Bv > 255) ? 255 : Bv);
            RGBBuffer[writePos++] = (Gv < 0) ? 0 : ((Gv > 255) ? 255 : Gv);
            RGBBuffer[writePos++] = (Rv < 0) ? 0 : ((Rv > 255) ? 255 : Rv);
        }

        YBuffer += width;
        if (i%2 == 1)
        {
            UBuffer += width/2;
            VBuffer += width/2;
        }
    }
}

void Tester::onSnapShot()
{
    showText("***...SnapShot...***"); 
    QFileInfo fi(ui.leSnapShotPath->text());
    if(fi.isDir() || !fi.dir().exists() || !isValidFilename(fi.baseName()))
    {
        showText("\n***...Should specify a valid file name...***\n");
        return;
    }

    if( !ui.leSnapShotPath->text().endsWith(".bmp", Qt::CaseInsensitive) &&
        !ui.leSnapShotPath->text().endsWith(".jpg", Qt::CaseInsensitive))
    {
        fi.setFile(fi.dir(), fi.baseName());
        ui.leSnapShotPath->setText(fi.filePath() + ".jpg");
    }

    Np_Result_t ret = Np_Result_NO_DATA;
    uchar* render_buf = m_pRender->GetBuffer(0);
    if(render_buf != NULL)
    {
        int width = m_pRender->GetWidth(0), 
            height = m_pRender->GetHeight(0),
            len = width * height * 3;
        char* buf = new char[len];
        
        if (kPixelFormatYUV420P == m_videoPixelFmt)
        {
            Yuv2Rgb(width, height, render_buf, (BYTE*)buf);
        }
        else
        {
            memcpy(buf, render_buf, len);
        }
        ret = Utility_SaveSnapShotImage(ui.leSnapShotPath->text().toStdWString().c_str(), buf, len, width, height);

        delete [] buf;
    }
    showResult(ret);

    if(Np_Result_OK == ret)
    {
        if(!m_lvsessions.empty())
        {
            Np_ID id = m_lvsessions.back()->id;
            Np_DateTime now;
            convertTime(QDateTime::currentDateTime(), now);
            ret = Utility_AddImageWaterMark(ui.leSnapShotPath->text().toStdWString().c_str(), now, GetCameraName(id).toStdWString().c_str());
        }
        else if(!m_pbsessions.empty())
        {
            Np_ID id = m_pbsessions.back()->id;
            Np_DateTime pb_time;
            PlayBack_GetTime(m_pbplayer, pb_time);
            ret = Utility_AddImageWaterMark(ui.leSnapShotPath->text().toStdWString().c_str(), pb_time, GetCameraName(id).toStdWString().c_str());
        }
    }
}

void Tester::onSnapShotPath()
{
    ui.leSnapShotPath->setText(QFileDialog::getSaveFileName(this, "SnapShot", ui.leSnapShotPath->text(), "Images (*.bmp *.jpg)", 0, 0));
}

void Tester::onCreateLVPlayer()
{
    showText("***...CreateLVPlayer...***");    
    Np_Result_t ret = Np_Result_OK;       
    ret = LiveView_CreatePlayer(
        m_handle,
        &m_lvplayer
        );
    showResult(ret); 
}
void Tester::onAttachSession()
{
    showText("***...AttachSession...***");    
    Np_Result_t ret = Np_Result_OK;    
    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    std::vector<stSession*>::iterator ite = m_lvsessions.begin();

    for(; ite != m_lvsessions.end(); ++ite)
    {
        if ((*ite)->id.centralID == id.centralID && (*ite)->id.localID == id.localID)
        {
            showText("***...Already attach this session...***");
            return;
        }
    }
    Np_StreamProfile profileID = checkStreamProfile(ui.cbbProfileSelect->currentText());
   
    stSession* pst = new stSession();
    pst->id = id;
    pst->pInst = this;
    pst->width = pst->height = 0;

    showID("Attach ID:",id);
    ret = LiveView_AttachSessionExt(
        m_lvplayer,
        &(pst->session),
        id,
        profileID,
        m_videoPixelFmt,
        VideoHandle,pst,
        AudioHandle,pst,
        ErrorHandle,pst
        );

    if (Np_Result_OK ==ret)
    {
        m_lvsessions.push_back(pst);
        SetLiveviewPTZUIStatus(&id);
#ifdef WIN32
    if(m_SoundDev)
    {
        m_SoundDev->StartPlay();
    }
#endif
}
    else
    {
        delete pst;
    }

    showResult(ret);
}
void Tester::onDetachSession()
{
#ifdef WIN32
    if(m_SoundDev)
    {
        m_SoundDev->StopPlay();
    }
#endif

    showText("***...DetachSession...***");    
    Np_Result_t ret = Np_Result_OK; 

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    std::vector<stSession*>::iterator ite = m_lvsessions.begin();

    for(; ite != m_lvsessions.end(); ++ ite)
    {
        if ((*ite)->id.centralID == id.centralID && (*ite)->id.localID == id.localID)
        {
            ret = LiveView_DetachSession(
                m_lvplayer,
                (*ite)->session       
                );
            showResult(ret);
            delete *ite;
            m_lvsessions.erase(ite);
            if (!m_lvsessions.empty())
            {
                SetLiveviewPTZUIStatus(&(m_lvsessions[m_lvsessions.size()-1]->id));
            }
            else
            {
                SetLiveviewPTZUIStatus(NULL);
            }
            return;
        }
    }
    showText("***...No Such session...***");    
}
void Tester::onSetAudioOn()
{
    showText("***...SetAudioOn...***");    
    Np_Result_t ret = Np_Result_OK;
    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();
    std::vector<stSession*>::iterator ite = m_lvsessions.begin();

    for(; ite != m_lvsessions.end(); ++ ite)
    {
         if ((*ite)->id.centralID == id.centralID && (*ite)->id.localID == id.localID)
         {
             ret = LiveView_SetAudioOn(
                 m_lvplayer,
                 (*ite)->session      
                 );
             showResult(ret);  
             return;
         }
    }

    showResult(Np_Result_INVALID_ARGUMENT);
}
void Tester::onSetAudioOff()
{
    showText("***...SetAudioOff...***");    
    Np_Result_t ret = Np_Result_OK;    
    ret = LiveView_SetAudioOff(
        m_lvplayer        
        );
    showResult(ret);  
}
void Tester::onDestroyLVPlayer()
{
    showText("***...DestroyLVPlayer...***");    
    Np_Result_t ret = Np_Result_OK;    
    ret = LiveView_DestroyPlayer(
        m_lvplayer        
        );
    showResult(ret);
    m_lvsessions.clear();
    m_lvplayer  = NULL;
}
void Tester::onTestLiveview()
{
    onCreateHandle();
    onCreateLVPlayer();
    onAttachSession();       
    onDetachSession();
    onSetAudioOn();    
    onSetAudioOff();
    onDestroyLVPlayer();
    onDestroyHandle();
}

void Tester::onPTZLeft()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;
    memset(&ptzParam, 0, sizeof(ptzParam));
    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    
    ptzMoveDirection.pan = kPanLeft;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onPTZDown()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;
    
    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    ptzMoveDirection.tilt = kTiltDown;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onPTZUp()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;

    memset(&ptzParam, 0, sizeof(ptzParam));
    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    // ptzMoveDirection indicates the direction of the movement
    ptzMoveDirection.tilt = kTiltUp;
    // ptzParam.command specifies the command to drive the PTZ
    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    // Select the camera of interest and provide the specified command
    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300); //some 
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onPTZRight()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;
    
    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    ptzMoveDirection.pan = kPanRight;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onPTZHome()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;

    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));

    ptzParam.command = kPTZHome;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onZoomIn()
{
    // TODO: Add your control notification handler code here
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;

    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    ptzMoveDirection.zoom = kZoomIn;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onZoomOut()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;
    
    memset(&ptzParam, 0, sizeof(ptzParam));
    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));

    ptzMoveDirection.zoom = kZoomOut;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onFocusFar()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;
    
    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    ptzMoveDirection.focus = kFocusFar;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();
    
    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);

    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::onFocusNear()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZContinuousMove ptzMoveDirection;

    memset(&ptzParam, 0, sizeof(ptzParam));

    memset(&ptzMoveDirection, 0, sizeof(ptzMoveDirection));
    ptzMoveDirection.focus = kFocusNear;

    ptzParam.command = kPTZContinuousMove;
    ptzParam.param.move = &ptzMoveDirection;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    TesterSleep(300);
    StopPTZ(ptzParam, ptzMoveDirection);
}

void Tester::StopPTZ(Np_PTZControlParam_CS ptzControlParam, const Np_PTZContinuousMove& ptzMoveCommand)
{
    ptzControlParam.command = kPTZStop;
    //Stop the previous PTZ command
    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();
    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzControlParam);
}

void Tester::onGetPTZPreset()
{
    showText("***...GetPTZPreset...***");    

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Np_Result_t ret = Np_Result_OK;
    Np_PTZPreset_CS_List ptzPresetList;
    ret = Info_GetPTZPreset_CS(
        m_handle,
        id,
        ptzPresetList
        );
    showPTZPresetList(ptzPresetList);
    showResult(ret);  
    Info_ReleasePTZPreset_CS(m_handle, ptzPresetList);
}

void Tester::onPresetGo()
{
    showText("***...PresetGo...***");

    Np_PTZControlParam_CS ptzParam;
    Np_PTZPreset_CS ptzPreset;

    memset(&ptzParam, 0, sizeof(ptzParam));
    ptzPreset.presetName = L"";
    ptzPreset.presetNo = 0;

    ptzPreset.presetNo = ui.lePresetNum->text().toInt();

    ptzParam.command = kPTZPresetGo;
    ptzParam.param.preset = &ptzPreset;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Np_Result_t ret = Np_Result_OK;
    ret = Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    showResult(ret);
}

void Tester::onPresetSet()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZPreset_CS ptzPreset;

    memset(&ptzParam, 0, sizeof(ptzParam));
    int nameSize = ui.lePresetSetName->text().length();
    ptzPreset.presetName = new wchar_t[nameSize + 1];
    memset(ptzPreset.presetName, 0, nameSize + 1);
    ptzPreset.presetNo = 0;

    ui.lePresetSetName->text().toWCharArray(ptzPreset.presetName);
    ptzPreset.presetName[nameSize] = L'\0';

    ptzParam.command = kPTZPresetSet;
    ptzParam.param.preset = &ptzPreset;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Np_Result_t ret = Np_Result_OK;
    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    showResult(ret);

    delete [] ptzPreset.presetName;
}

void Tester::onPresetClear()
{
    Np_PTZControlParam_CS ptzParam;
    Np_PTZPreset_CS ptzPreset;

    memset(&ptzParam, 0, sizeof(ptzParam));
    ptzPreset.presetName = L"";
    ptzPreset.presetNo = 0;

    ptzPreset.presetNo = ui.lePresetNum->text().toInt();

    ptzParam.command = kPTZPresetClear;
    ptzParam.param.preset = &ptzPreset;

    Np_ID id;
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    Np_Result_t ret = Np_Result_OK;
    Control_PTZ_PTZDeviceID_CS(m_handle, id, &ptzParam);
    showResult(ret);
}

void Tester::onGetDIStatus()
{
    Np_ID id;
    Np_DIOStatus status = kDIO_OFF;
    Np_Result_t ret = Np_Result_OK;    
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    for (unsigned int i = 0; i < m_deviceList.PhysicalGroup.size; ++i)
    {
        Np_Device_CS_List& camDeviceList = m_deviceList.PhysicalGroup.items[i].Camera;
        for (unsigned int j = 0; j < camDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DIDevices = camDeviceList.items[j].DIDevices;
            for (unsigned int k = 0; k < DIDevices.size; ++k)
            {
                if (DIDevices.items[k].ID.centralID == id.centralID &&
                    DIDevices.items[k].ID.localID == id.localID)
                 {
                     showText("***...Show DI Status...***"); 

                     ret = Info_GetDIOStatus(m_handle, id, status);

                     showResult(ret);
                     QString str;
                     str = QString(
                         "DI Status = %1\n"
                         )
                         .arg(status);
                     showText(str);
                     showText("==========\n"); 
                     return;
                 }
            }
        }

        Np_Device_CS_List& ioBoxDeviceList = m_deviceList.PhysicalGroup.items[i].IOBox;
        for (unsigned int j = 0; j < ioBoxDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DIDevices = ioBoxDeviceList.items[j].DIDevices;
            for (unsigned int k = 0; k < DIDevices.size; ++k)
            {
                if (DIDevices.items[k].ID.centralID == id.centralID &&
                    DIDevices.items[k].ID.localID == id.localID)
                {
                    showText("***...Show DI Status...***"); 

                    ret = Info_GetDIOStatus(m_handle, id, status);

                    showResult(ret);
                    QString str;
                    str = QString(
                        "DI Status = %1\n"
                        )
                        .arg(status);
                    showText(str);
                    showText("==========\n"); 
                    return;
                }
            }
        }
    }
   
    showText("***...No this DI device...***\n"); 
}

void Tester::onGetDOStatus()
{
    Np_ID id;
    Np_DIOStatus status = kDIO_OFF;
    Np_Result_t ret = Np_Result_OK;    
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    for (unsigned int i = 0; i < m_deviceList.PhysicalGroup.size; ++i)
    {
        Np_Device_CS_List& camDeviceList = m_deviceList.PhysicalGroup.items[i].Camera;
        for (unsigned int j = 0; j < camDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DODevices = camDeviceList.items[j].DODevices;
            for (unsigned int k = 0; k < DODevices.size; ++k)
            {
                if (DODevices.items[k].ID.centralID == id.centralID &&
                    DODevices.items[k].ID.localID == id.localID)
                {
                    showText("***...Show DO Status...***"); 

                    ret = Info_GetDIOStatus(m_handle, id, status);

                    showResult(ret);
                    QString str;
                    str = QString(
                        "DO Status = %1\n"
                        )
                        .arg(status);
                    showText(str);
                    showText("==========\n");
                    return;
                }
            }
        }

        Np_Device_CS_List& ioboxDeviceList = m_deviceList.PhysicalGroup.items[i].IOBox;
        for (unsigned int j = 0; j < ioboxDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DODevices = ioboxDeviceList.items[j].DODevices;
            for (unsigned int k = 0; k < DODevices.size; ++k)
            {
                if (DODevices.items[k].ID.centralID == id.centralID &&
                    DODevices.items[k].ID.localID == id.localID)
                {
                    showText("***...Show DO Status...***"); 

                    ret = Info_GetDIOStatus(m_handle, id, status);

                    showResult(ret);
                    QString str;
                    str = QString(
                        "DO Status = %1\n"
                        )
                        .arg(status);
                    showText(str);
                    showText("==========\n");
                    return;
                }
            }
        }
    }
    
    showText("***...No this DO device...***\n"); 
}

void Tester::onControlDigitalOutput()
{
    Np_ID id;
    Np_Result_t ret = Np_Result_OK;    
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    for (unsigned int i = 0; i < m_deviceList.PhysicalGroup.size; ++i)
    {
        Np_Device_CS_List& camDeviceList = m_deviceList.PhysicalGroup.items[i].Camera;
        for (unsigned int j = 0; j < camDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DODevices = camDeviceList.items[j].DODevices;
            for (unsigned int k = 0; k < DODevices.size; ++k)
            {
                if (DODevices.items[k].ID.centralID == id.centralID &&
                    DODevices.items[k].ID.localID == id.localID)
                {
                    showText("***...Control Digital Output...***"); 
                    ret = Control_DigitalOutput(
                        m_handle, 
                        id, 
                        checkDOControl(ui.cbbDOControl->currentText())
                        );

                    QString str;
                    str = QString("%1 DO\n").arg(ui.cbbDOControl->currentText());
                    showText(str);
                    showResult(ret);
                    return;
                }
            }
        }

        Np_Device_CS_List& ioboxDeviceList = m_deviceList.PhysicalGroup.items[i].IOBox;
        for (unsigned int j = 0; j < ioboxDeviceList.size; ++j)
        {
            Np_SubDevice_CS_List& DODevices = ioboxDeviceList.items[j].DODevices;
            for (unsigned int k = 0; k < DODevices.size; ++k)
            {
                if (DODevices.items[k].ID.centralID == id.centralID &&
                    DODevices.items[k].ID.localID == id.localID)
                {
                    showText("***...Control Digital Output...***"); 
                    ret = Control_DigitalOutput(
                        m_handle, 
                        id, 
                        checkDOControl(ui.cbbDOControl->currentText())
                        );

                    QString str;
                    str = QString("%1 DO\n").arg(ui.cbbDOControl->currentText());
                    showText(str);
                    showResult(ret);
                    return;
                }
            }
        }
    }
    showText("***...No this DO device...***\n"); 
}

void Tester::onGetSensorProfileList()
{
    Np_ID id;
    Np_Result_t ret = Np_Result_OK;    
    id.centralID = ui.leCentralID->text().toInt();
    id.localID = ui.leLocalID->text().toInt();

    for (unsigned int i = 0; i < m_deviceList.PhysicalGroup.size; ++i)
    {
        for (unsigned int j = 0; j < m_deviceList.PhysicalGroup.items[i].Camera.size; ++j)
        {
            for (unsigned int k = 0; k < m_deviceList.PhysicalGroup.items[i].Camera.items[j].SensorDevices.size; ++k)
            {
                if (m_deviceList.PhysicalGroup.items[i].Camera.items[j].SensorDevices.items[k].ID.centralID == id.centralID &&
                    m_deviceList.PhysicalGroup.items[i].Camera.items[j].SensorDevices.items[k].ID.localID == id.localID)
                {
                    Np_SensorProfile_CS_List profileList;
                    showText("***...Get Sensor Profile List...***"); 
                    ret = Info_GetSensorProfileList_CS(
                        m_handle, 
                        id, 
                        profileList
                        );
                    showSensorProfileList(profileList);
                    showResult(ret);
                    Info_ReleaseSensorProfileList_CS(m_handle, profileList);
                    return;
                }
            }
        }
    }
    showText("***...No this Sensor device...***\n"); 
}

void Tester::onCreatePBPlayer()
{
    showText("***...CreatePBPlayer...***");    
    Np_Result_t ret = Np_Result_OK;           
    ret = PlayBack_CreatePlayer(
        m_handle,
        &m_pbplayer
        );
    showResult(ret);  

    if(Np_Result_OK == ret)
    {
        SetExportProfileList();
    }
}
void Tester::onAttachPBSession()
{
    showText("***...AttachSession...***");       
    Np_Result_t ret = Np_Result_OK;    
    Np_ID id;
    id.centralID = ui.lePBCentralID->text().toInt();
    id.localID = ui.lePBLocalID->text().toInt();
    showID("Attach ID:",id);

    stSession* pst = new stSession();
    pst->id = id;
    pst->pInst = this;
    pst->width = pst->height = 0;

    ret = PlayBack_AttachSessionExt(
        m_pbplayer,
        &(pst->session),
        id,
        m_videoPixelFmt,
        VideoHandle,pst,
        AudioHandle,pst,
        ErrorHandle,pst
        );

    if (Np_Result_OK ==ret)
    {
        m_pbsessions.push_back(pst);
    }
    else
    {
        delete pst;
    }
    showResult(ret);  

#ifdef WIN32
    if(m_SoundDev)
    {
        m_SoundDev->StartPlay();
    }
#endif    
}
void Tester::onDetachPBSession()
{
#ifdef WIN32
    if(m_SoundDev)
    {
        m_SoundDev->StopPlay();
    }
#endif

    showText("***...DetachSession...***");    
    Np_Result_t ret = Np_Result_OK;

    Np_ID id;
    id.centralID = ui.lePBCentralID->text().toInt();
    id.localID = ui.lePBLocalID->text().toInt();

    std::vector<stSession*>::iterator ite = m_pbsessions.begin();

    for(; ite != m_pbsessions.end(); ++ ite)
    {
        if ((*ite)->id.centralID == id.centralID && (*ite)->id.localID == id.localID)
        {
            ret = PlayBack_DetachSession(
                m_pbplayer,
                (*ite)->session        
                );
            showResult(ret);  
            delete *ite;
            m_pbsessions.erase(ite);
            return;
        }
    }

    ret = PlayBack_DetachSession(
        m_pbplayer,
        NULL       
        );
    showResult(ret);  
   
}
void Tester::onPBSeek()
{
    showText("***...Seek...***");    
    Np_Result_t ret = Np_Result_OK;  
    Np_DateTime time;
    convertTime(ui.dateTimeEditFrom->dateTime(),time);
    showTime("Seek Time", time);
    ret = PlayBack_Seek(
        m_pbplayer,
        time
        );
    showResult(ret);  
}
void Tester::onPBOpenRecord()
{
    showText("***...OpenRecord...***");    
    Np_Result_t ret = Np_Result_OK;  
    Np_DateTime starttime;        
    Np_DateTime endtime;
    if (ui.dateTimeEditFrom->dateTime() > ui.dateTimeEditTo->dateTime())
    {
        showText("\n***...StartTime can't large than EndTime...***\n");
        return;
    }
    convertTime(ui.dateTimeEditFrom->dateTime(),starttime);
    convertTime(ui.dateTimeEditTo->dateTime(),endtime);
    showTime("start time",starttime);    
    showTime("end time",endtime);
    ret = PlayBack_OpenRecord(
        m_pbplayer,
        starttime,
        endtime
        );
    showResult(ret);  
}
void Tester::onPBSetSpeed()
{
    showText("***...SetSpeed...***");    
    Np_Result_t ret = Np_Result_OK;  
    showText("Speed:");
    showText(QString::number(ui.PBSpeed->value()));
    ret = PlayBack_SetSpeed(
        m_pbplayer,     
        (float)(ui.PBSpeed->value())
        );
    showResult(ret);  
}
void Tester::onPBPause()
{
    showText("***...Pause...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_Pause(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBPlay()
{
    showText("***...Play...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_Play(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBReverse()
{
    showText("***...ReversePlay...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_ReversePlay(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBForward()
{
    showText("***...StepForward...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_StepForward(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBBackward()
{
    showText("***...StepBackward...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_StepBackward(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBNext()
{
    showText("***...Next...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_Next(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onPBPrevious()
{
    showText("***...Previous...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_Previous(
        m_pbplayer       
        );
    showResult(ret);  
}
void Tester::onDestroyPBPlayer()
{
    showText("***...DestroyPlayer...***");    
    Np_Result_t ret = Np_Result_OK;      
    ret = PlayBack_DestroyPlayer(
        m_pbplayer       
        );
    m_pbplayer = NULL;
    m_pbsessions.clear();
    showResult(ret);  
}
void Tester::onTestPlayBack()
{
    onCreateHandle();
    onCreatePBPlayer();
    onAttachPBSession();    
    onPBSeek();    
    onPBSetSpeed();
    onPBPause();
    onPBPlay();
    onPBReverse();
    onPBForward();
    onPBBackward();
    onPBNext();
    onPBPrevious();    
    onPBOpenRecord();
    //onPBSetSpeed();
    //onPBPause();
    //onPBPlay();
    //onPBReverse();
    //onPBForward();
    //onPBBackward();
    //onPBNext();
    //onPBPrevious(); 
    onDetachPBSession();
    onDestroyPBPlayer();
    onDestroyHandle();
}

void Tester::onPBExport()
{
    showText("***...ExportVideo...***");
    Np_Result_t ret = Np_Result_OK;

    if (ui.dateTimeEditFrom->dateTime() > ui.dateTimeEditTo->dateTime())
    {
        showText("\n***...StartTime shouldn't be larger than EndTime...***\n");
        return;
    }

    if(ui.cbbPBExportProfile->count() <= 0)
    {
        showText("\n***...No profile supported, unable to export video...***\n");
        return;
    }

    Np_ExportContent content;
    m_exptctx.pInst = this;
    content.id.centralID = m_exptctx.id.centralID = ui.lePBCentralID->text().toInt();
    content.id.localID = m_exptctx.id.localID = ui.lePBLocalID->text().toInt();

    convertTime(ui.dateTimeEditFrom->dateTime(), content.startTime);
    convertTime(ui.dateTimeEditTo->dateTime(), content.endTime);

    for(std::vector<stSession*>::iterator ite = m_pbsessions.begin();
        ite != m_pbsessions.end(); ++ite)
    {
        if(m_exptctx.id.centralID == (*ite)->id.centralID && m_exptctx.id.localID == (*ite)->id.localID)
        {
            m_exptctx.width = content.width = (*ite)->width;
            m_exptctx.height = content.height = (*ite)->height;
            break;
        }
    }

    content.excludeAudio = ui.cbPBExportExcludeAudio->isChecked();

    QVariant var = ui.cbbPBExportProfile->itemData(ui.cbbPBExportProfile->currentIndex());
    int profile = var.toInt();
    QFileInfo fi(ui.lePBExportPath->text());
    if(fi.isDir() || !fi.dir().exists() || !isValidFilename(fi.baseName()))
    {
        showText("\n***...Should specify a valid file name...***\n");
        return;
    }
    
    fi.setFile(fi.dir(), fi.baseName());
    ui.lePBExportPath->setText(FormatExportFilePath(fi.filePath(), -1, ui.cbbPBExportProfile->currentText()));

    ret = PlayBack_ExportVideo( m_pbplayer, content, fi.filePath().toStdWString().c_str(), 
                                profile / 100, profile % 100, ExportHandle, &m_exptctx, OSDHandle, &m_exptctx);
    showResult(ret);
    m_bExporting = (Np_Result_OK == ret);
}

void Tester::onPBStopExport()
{
    showText("***...StopExport...***");
    Np_Result_t ret = Np_Result_OK;

    ret = PlayBack_StopExport(m_pbplayer);
    showResult(ret);

    QFileInfo fi(ui.lePBExportPath->text());
    fi.setFile(fi.dir(), fi.baseName());
    QFile file(FormatExportFilePath(fi.filePath(), 0, ui.cbbPBExportProfile->currentText()));
    if(file.exists())
    {
        file.remove();
    }
    m_bExporting = false;
    ui.PBExportProgress->setValue(0);
}

void Tester::onPBExportPath()
{
#ifdef __APPLE__
    QString filter = "Videos (*.mov)";
#else
    QString filter = "Videos (*.asf *.avi)";
#endif
    QFileInfo fi(QFileDialog::getSaveFileName(this, "Export Video", ui.lePBExportPath->text(), filter, 0, 0));
    fi.setFile(fi.dir(), fi.baseName());
    ui.lePBExportPath->setText(fi.filePath());
}

void Tester::OnUpdateFrame()
{
    m_pGridsView->UpdateGridsView();
}

void Tester::OnUpdateUI()
{
    if (!m_pbsessions.empty())
    {
        Np_DateTime dateTime;
        PlayBack_GetTime(m_pbplayer, dateTime);
        float fSpeed = 1.0;
        PlayBack_GetSpeed(m_pbplayer, fSpeed);

        Np_PlayerState state = kStateStopped;
        QString StateStr = "";
        PlayBack_GetPlayerState(m_pbplayer, state);
        switch(state)
        {
            case kStateStopped:
            {
                StateStr = "Stopped";
                break;
            }
            case kStatePaused:
            {
                StateStr = "Paused";
                break;
            }
            case kStateRunning:
            {
                StateStr = "Running";
                break;
            }
            default:
            {
                StateStr = "";
                break;
            }
        }

        QString strTime;
        strTime = QString(
            "Time : %1\\"
            "%2\\"
            "%3 "
            "%4:"
            "%5:"
            "%6  "
            "Speed : %7 "
            "State : %8"
            )
            .arg(dateTime.year, 4, 10, QChar('0'))
            .arg(dateTime.month, 2, 10, QChar('0'))
            .arg(dateTime.day, 2, 10, QChar('0'))
            .arg(dateTime.hour, 2, 10, QChar('0'))
            .arg(dateTime.minute, 2, 10, QChar('0'))
            .arg(dateTime.second, 2, 10, QChar('0'))
            .arg(fSpeed)
            .arg(StateStr);
        ui.labelTime->setText(strTime);

        SetPlaybackButtonStatus(m_bPBFileOpen);
    }

    OnUpdateExportStatus();
}

void Tester::OnUpdateExportStatus()
{
    m_exptcbmutex.lock();
    if(!m_exptcbinfos.empty())
    {
        ExportCbInfo info = m_exptcbinfos.front();
        m_exptcbinfos.pop_front();
        if (info.error == kExportUpdateProgress)
        {
            while(!m_exptcbinfos.empty())
            {
                ExportCbInfo next = m_exptcbinfos.front();
                if(kExportUpdateProgress != next.error || info.percent != next.percent)
                {
                    break;
                }
                m_exptcbinfos.pop_front();
            }
            ui.PBExportProgress->setValue(info.percent);
            m_exptcbmutex.unlock();
            return;
        }
        else if(info.error == kExportFormatChange)
        {
            AddWaterMarkAfterExport(info.id, info.iFormatChangedIndex);
            m_exptcbmutex.unlock();
            return;
        }

        switch(info.error)
        {
        case kExportSuccess:
            AddWaterMarkAfterExport(info.id, info.iFormatChangedIndex);
            showText("Export Success");
            break;
        case kExportCallbackError:
            showText("Export Callback Error");
            break;
        case kExportChannelEmpty:
            showText("Export Channel Empty");
            break;
        case kExportCueTimeError:
            showText("Export CueTime Error");
            break;
        case kExportDimesionError:
            showText("Export Dimension Error");
            break;
        case kExportNoData:
            showText("No Data to Export");
            break;
        case kExportFail:
            showText("Export Fail");
            if(ui.cbbPBExportProfile->count() > 0)
            {
                QFileInfo fi(ui.lePBExportPath->text());
                fi.setFile(fi.dir(), fi.baseName());
                QFile file(FormatExportFilePath(fi.filePath(), info.iFormatChangedIndex, ui.cbbPBExportProfile->currentText()));
                if(file.exists())
                {
                    file.remove();
                }
            }
            break;
        case kExportMJpegMac:
            showText("Export MJPEG to MOV format is not supported");
            break;
        }
        m_bExporting = false;
        ui.PBExportProgress->setValue(0);
        m_exptcbinfos.clear();
    }
    m_exptcbmutex.unlock();

    if((ui.cbbPBExportProfile->count() > 0) && m_bPBFileOpen)
    {
        ui.btnPBExport->setEnabled(!m_bExporting);
        ui.btnPBStopExport->setEnabled(m_bExporting);
    }
}

void Tester::SetPlaybackButtonStatus(bool bFileOpen)
{
    ui.btnPBPlay->setEnabled(bFileOpen);
    ui.btnPBPause->setEnabled(bFileOpen);
    ui.btnPBPrevious->setEnabled(bFileOpen);
    ui.btnPBNext->setEnabled(bFileOpen);
    ui.btnPBSeek->setEnabled(bFileOpen);
    ui.btnPBForward->setEnabled(bFileOpen);
    ui.btnPBBackward->setEnabled(bFileOpen);
}

void Tester::SetLiveviewPTZUIStatus(const Np_ID* camID)
{

    long long ptzCap = 0;
    Np_DeviceList_CS deviceList;

    if (NULL != camID)
    {
        if(Np_Result_OK == Info_GetDeviceList_CS(m_handle, deviceList))
        {
            for (int i=0; i<deviceList.PhysicalGroup.size; ++i)
            {
                Np_Device_CS_List& camList = deviceList.PhysicalGroup.items[i].Camera;
                for (int j=0; j<camList.size; ++j)
                {
                    if (camID->centralID == camList.items[j].ID.centralID &&
                        camID->localID == camList.items[j].ID.localID)
                    {
                        if (camList.items[j].PTZDevices.size)
                        {
                            Info_GetPTZCapability(m_handle, camList.items[j].PTZDevices.items[0].ID, ptzCap);
                        }
                    }
                }
            }

            Info_ReleaseDeviceList_CS(m_handle, deviceList);
        }
    }

    ui.btnZoomIn->setEnabled(ptzCap & kPTZZoom);
    ui.btnZoomout->setEnabled(ptzCap & kPTZZoom);

    ui.btnFocusNear->setEnabled(ptzCap & kPTZFocus);
    ui.btnFocusFar->setEnabled(ptzCap & kPTZFocus);

    ui.btnPTZUp->setEnabled(ptzCap & kPTZTilt);
    ui.btnPTZDown->setEnabled(ptzCap & kPTZTilt);

    ui.btnPTZLeft->setEnabled(ptzCap & kPTZPane);
    ui.btnPTZRight->setEnabled(ptzCap & kPTZPane);

    ui.btnPTZHome->setEnabled(ptzCap);

    ui.btnGetPTZPreset->setEnabled(ptzCap);
    ui.btnPresetGo->setEnabled(ptzCap);
    ui.btnPresetClear->setEnabled(ptzCap);
    ui.btnPresetSet->setEnabled(ptzCap);
    ui.label_16->setEnabled(ptzCap);
    ui.lePresetNum->setEnabled(ptzCap);
    ui.label_18->setEnabled(ptzCap);
    ui.lePresetSetName->setEnabled(ptzCap);

}

void Tester::SetPBFileOpen(bool bFileOpen)
{
    m_bPBFileOpen = bFileOpen;
}

void Tester::PutExportCbInfo(Np_ID id, Np_ExportError error, unsigned int percent, int iFormateChangedIndex)
{
    m_exptcbmutex.lock();
    m_exptcbinfos.push_back(ExportCbInfo(id, error, percent, iFormateChangedIndex));
    m_exptcbmutex.unlock();
}

void Tester::TesterSleep(long long mSec)
{
#ifdef WIN32
    Sleep(mSec);
#else
    struct timeval currentTime;
    gettimeofday(&currentTime, 0);
    struct timespec waitTime;
    waitTime.tv_sec = currentTime.tv_sec + mSec/1000;
    waitTime.tv_nsec = (currentTime.tv_usec*1000) + ((mSec%1000)*1000000);
    
    pthread_mutex_t mtx;
    pthread_cond_t cnd;
    pthread_mutex_init(&mtx, 0);
    pthread_cond_init(&cnd, 0);
    pthread_mutex_lock(&mtx);
    (void)pthread_cond_timedwait(&cnd, &mtx, &waitTime);
    pthread_mutex_unlock(&mtx);
    pthread_cond_destroy(&cnd);
    pthread_mutex_destroy(&mtx);
#endif
}

void Tester::AdjustTesterUI()
{
    QString dateTimeFormat = "yyyy/M/d AP hh:mm:ss";
    QString dateFormat = "yyyy/M/d";
    ui.dateTimeEditFrom->setDisplayFormat(dateTimeFormat);
    ui.dateTimeEditTo->setDisplayFormat(dateTimeFormat);
    ui.pbDateEditQuery->setDisplayFormat(dateFormat);
}

void Tester::SetExportProfileList()
{
    Np_ExportFormatList fmtlist;
    Np_Result_t ret = PlayBack_GetExportFormatList(m_pbplayer, fmtlist);
    if(Np_Result_OK == ret)
    {
        ui.cbbPBExportProfile->clear();
        for(int i = 0; i < fmtlist.size; ++i)
        {
            QString desc_base = QString::fromWCharArray(fmtlist.items[i].description);
            int value_base = fmtlist.items[i].format * 100; //Assume profile list won't exceed 99
            if(0 == fmtlist.items[i].supportedProfile.size)
            {
                ui.cbbPBExportProfile->addItem( desc_base, value_base);
                continue;
            }

            for(int j = 0; j < fmtlist.items[i].supportedProfile.size; ++j)
            {
                ui.cbbPBExportProfile->addItem( desc_base + " - " + QString::fromWCharArray(fmtlist.items[i].supportedProfile.items[j].description), 
                                                value_base + fmtlist.items[i].supportedProfile.items[j].profile);
            }
        }
        ret = PlayBack_ReleaseExportFormatList(m_pbplayer, fmtlist);
    }
}

void Tester::AddWaterMarkAfterExport(Np_ID id, int iFormatChangedIndex)
{
    QFileInfo fi(ui.lePBExportPath->text());
    fi.setFile(fi.dir(), fi.baseName());
    QString qfilpath = FormatExportFilePath(fi.filePath(), iFormatChangedIndex, ui.cbbPBExportProfile->currentText());
    Np_DateTime startTime, endTime;
    convertTime(ui.dateTimeEditFrom->dateTime(), startTime);
    convertTime(ui.dateTimeEditTo->dateTime(), endTime);

    QString camera_name = GetCameraName(id);

    Utility_AddVideoWaterMark(qfilpath.toStdWString().c_str(), startTime, endTime, camera_name.toStdWString().c_str());
}

QString Tester::GetCameraName(Np_ID id)
{
    Np_Result_t ret = Np_Result_OK;    
    for (unsigned int i = 0; i < m_deviceList.PhysicalGroup.size; ++i)
    {
        Np_Device_CS_List camDeviceList = m_deviceList.PhysicalGroup.items[i].Camera;
        for (unsigned int j = 0; j < camDeviceList.size; ++j)
        {
            if (camDeviceList.items[j].ID.centralID == id.centralID &&
                camDeviceList.items[j].ID.localID == id.localID)
            {
                return QString::fromWCharArray(camDeviceList.items[j].name);
            }
            
            Np_SubDevice_CS_List SensorDevices = camDeviceList.items[j].SensorDevices;
            for (unsigned int k = 0; k < SensorDevices.size; ++k)
            {
                if (SensorDevices.items[k].ID.centralID == id.centralID &&
                    SensorDevices.items[k].ID.localID == id.localID)
                {
                    return QString::fromWCharArray(SensorDevices.items[k].name);
                }
            }
        }
    }

    return QString("");
}