/**********************************************************************************************
    Copyright (C) 2007 Oliver Eichler oliver.eichler@gmx.de

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA

  Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd.
  or one of its subsidiaries.

  LvD: whatGarmin is a query version that tries to find info about the
       device and writes it to the terminal screen.

       This assumes that the connected unit is a Garmin one and that
       the basic USB syncup can be achieved.

       Tell the user to download waypoints to use this, then turn off the
       unit.

  LvD: EOT

**********************************************************************************************/
#include "../Platform.h"
#include "CDevice.h"
#include <Garmin.h>

#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>

using namespace whatGarmin;
using namespace Garmin;
using namespace std;

CDevice::CDevice()
: usb(0)
{
    copyright = "<h1>QLandkarte Dummy Device Driver whatGarmin</h1>"
        "<h2>Driver I/F Ver. " INTERFACE_VERSION "</h2>"
        "<p>&#169; 2007 by Oliver Eichler (oliver.eichler@gmx.de)</p>"
        "<p>&#169; 2007 by Leon van Dommelen (dommelen@eng.fsu.edu)</p>"
        "<p>This driver is distributed in the hope that it will be useful, "
        "but WITHOUT ANY WARRANTY; without even the implied warranty of "
        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
        "GNU General Public License for more details. </p>";
}


CDevice::~CDevice()
{

}


void CDevice::_acquire()
{
    // activate the driver
    usb = new CUSB();
    usb->open();
    usb->syncup();

    // product data
    ostringstream note;

    // output the product name
    cout << "Product name: " << usb->getProductString().c_str() << endl;
    note  << "\n\n" << usb->getProductString().c_str();

    // output the product ID
    cout << "  product ID: " << usb->getProductId();
    note  << "\nproduct ID: " <<  usb->getProductId();

    // See what protocols are there

    // link protocol
    if (usb->getDataType(-1,'L',(uint16_t)1)) {
        cout << "  supports link protocol L001" << endl;
        note  << "\nlink protocol L001";
    }
    if (usb->getDataType(-1,'L',(uint16_t)2)) {
        cout << "  supports link protocol L002" << endl;
        note  << "\nlink protocol L002";
    }

    // command protocol
    if (usb->getDataType(-1,'A',(uint16_t)10)) {
        cout << "  supports command protocol A010" << endl;
        note  << "\ncommand protocol A010";
    }
    if (usb->getDataType(-1,'A',(uint16_t)11)) {
        cout << "  supports command protocol A011" << endl;
        note  << "\ncommand protocol A011";
    }

    // waypoint transfer protocol
    if (usb->getDataType(0,'A',(uint16_t)100)) {
        cout << "  supports waypoint transfer protocol A100 with D0=" << usb->getDataType(0,'A',(uint16_t)100) << endl;
        note  << "\nwaypoint protocol A100 D" << usb->getDataType(0,'A',(uint16_t)100);
    }
    if (usb->getDataType(0,'A',(uint16_t)101)) {
        cout << "  supports waypoint transfer protocol A101 with D0=" << usb->getDataType(0,'A',(uint16_t)101) << endl;
        note  << "\nwaypoint protocol A101 D" << usb->getDataType(0,'A',(uint16_t)101);
    }

    // proximity waypoint transfer protocol
    if (usb->getDataType(0,'A',(uint16_t)400)) {
        cout << "  supports proximity waypoint transfer protocol A400 with D0=" << usb->getDataType(0,'A',(uint16_t)400) << endl;
        note  << "\nproximity waypoint protocol A400 D" << usb->getDataType(0,'A',(uint16_t)400);
    }

    // track log transfer protocol
    if (usb->getDataType(0,'A',(uint16_t)300)) {
        cout << "  supports track log transfer protocol A300 with D0=" << usb->getDataType(0,'A',(uint16_t)300) << endl;
        note  << "\ntrack log protocol A300 D" << usb->getDataType(0,'A',(uint16_t)300);
    }
    if (usb->getDataType(0,'A',(uint16_t)301)) {
        cout << "  supports track log transfer protocol A301 with D0=" << usb->getDataType(0,'A',(uint16_t)301) << " D1=" << usb->getDataType(1,'A',(uint16_t)301) << endl;
        note  << "\ntrack log protocol A301 D" << usb->getDataType(0,'A',(uint16_t)301) << " D" << usb->getDataType(1,'A',(uint16_t)301);
    }
    if (usb->getDataType(0,'A',(uint16_t)302)) {
        cout << "  supports track log transfer protocol A302 with D0=" << usb->getDataType(0,'A',(uint16_t)302) << " D1=" << usb->getDataType(1,'A',(uint16_t)302) << endl;
        note  << "\ntrack log protocol A302 D" << usb->getDataType(0,'A',(uint16_t)302) << " D" << usb->getDataType(1,'A',(uint16_t)302);
    }

    // route transfer protocol
    if (usb->getDataType(0,'A',(uint16_t)200)) {
        cout << "  supports route transfer protocol A200 with D0=" << usb->getDataType(0,'A',(uint16_t)200) << " D1=" << usb->getDataType(1,'A',(uint16_t)200) << endl;
        note  << "\nroute protocol A200 D" << usb->getDataType(0,'A',(uint16_t)200) << " D" << usb->getDataType(1,'A',(uint16_t)200);
    }
    if (usb->getDataType(0,'A',(uint16_t)201)) {
        cout << "  supports route transfer protocol A201 with D0=" << usb->getDataType(0,'A',(uint16_t)201) << " D1=" << usb->getDataType(1,'A',(uint16_t)201)  << " D2=" << usb->getDataType(2,'A',(uint16_t)201) << endl;
        note  << "\nroute protocol A201 D" << usb->getDataType(0,'A',(uint16_t)201) << " D" << usb->getDataType(1,'A',(uint16_t)201) << " D" << usb->getDataType(2,'A',(uint16_t)201);
    }

    // PVT protocol
    if (usb->getDataType(0,'A',(uint16_t)800)) {
        cout << "  supports Position/Velocity/Time protocol A800 with D0=" << usb->getDataType(0,'A',(uint16_t)800) << endl;
        note  << "\nPVT protocol A800 D" << usb->getDataType(0,'A',(uint16_t)800);
    }

    // end of data
    cout << "Product Data End: " << usb->getProductString().c_str() << endl;

    // abort any action
    cout << note.str() << endl;
    throw exce_t(errSync,note.str());
}


void CDevice::_getDevProperties(Garmin::DevProperties_t& /*dev_properties*/)
{
    throw exce_t(errSync,"This method is not implemented for whatGarmin.");
}


void CDevice::_release()
{
    if(usb == 0) return;

    // close by resetting device
    usb->close2();

    delete usb;
    usb = 0;
}


const std::string& CDevice::getCopyright()
{
    lasterror = "";
    try
    {
        CMutexLocker lock(mutex);
        _acquire();
        _release();
    }
    catch(exce_t& e) {
        if(e.err != errBlocked) _release();
        lasterror = "Protocol dump: " + e.msg;
        throw (int)e.err;
    }

    return copyright;
}
