/*! @file

    @id $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#include <suisse-id-demo.hxx>
#include <mrw/args.hxx>

#include <QtNetwork/QSslCertificate>
#include <QtCore/QDateTime>
#include <QtCore/QStringList>

void show(const QString& s, const std::string& p="item: ") {
  std::cout<<p<<QString(s.toUtf8()).toStdString()<<std::endl;
}

void show(const QStringList& sl, const std::string& p="item: ") {
  for (QStringList::const_iterator s(sl.begin()); s!=sl.end(); ++s)
    std::cout<<p<<QString(s->toUtf8()).toStdString()<<std::endl;
}

// show certificate information
void show(const suisseid::Certificate& cert) {
// makes use of qt library's certificate class
  QSslCertificate c(QByteArray(cert.data(), cert.size()), QSsl::Der);
  std::cout<<"Certificate info:";
  show(c.subjectInfo(QSslCertificate::CommonName), "  CN=");
  std::cout<<"  Valid until: "
           <<QString(c.expiryDate().toString().toUtf8()).toStdString()
           <<std::endl;
}

// call with option -h for help
int main(int argc, char** argv) try {
  std::string lib("libcvP11.so"); // default pkcs#11/cryptoki library
  mrw::args::parse(argc, argv,
                   "Sign a text (optionally several times for performance"
                   " measurements).",
                   mrw::args::defaults()
                   <<mrw::args::decl("l", "library", "cryptoki library to load",
                                     mrw::args::decl::param_list()
                                     <<mrw::args::param(lib, "lib")));
  // now lib contains the dynamic library to load

  // scan for suisseid cards
  suisseid::Cards cards(suisseid::Scanner(lib).scan());
  for (suisseid::Cards::iterator card(cards.begin());
       card!=cards.end(); ++card) {
    std::string choice;
    while (choice!="n") try {
      std::cout<<"=================================================="<<std::endl
               <<"Found SuisseID:"<<std::endl
               <<"  Reader Name:   "<<(*card)->name()<<std::endl
               <<"  Version:       "<<(*card)->version()<<std::endl
               <<"  PIN-Length:    "<<(*card)->minimalPinLength()
               <<" - "<<(*card)->maximalPinLength()<<std::endl
               <<"  PIN retries:"<<std::endl
               <<"    PKCS#15:     "<<(*card)->pkcs15PinRetries()<<std::endl
               <<"    SigG:        "<<(*card)->sigGPinRetries()<<std::endl
               <<"    Transport:   "<<(*card)->transportPinRetries()<<std::endl
               <<"    PUK:         "<<(*card)->pukRetries()<<std::endl;
      cryptoki::Session::Info info((*card)->sessionInfo());
      std::cout<<"  Session:"<<std::endl
               <<"    Slot:        "<<info.slotID<<std::endl
               <<"    State:       "<<info.stateString()<<std::endl
               <<"    Flags:       "<<(info.readwrite()
                                       ?"read/write":"read only")<<std::endl
               <<"    Device Error: "<<info.ulDeviceError<<std::endl;
      suisseid::Certificates certs((*card)->certificates());
      std::cout<<"  Certificates:   "<<certs.size()<<std::endl;
      std::cout<<"--------------------------------------------------"<<std::endl
               <<"Your Order Sir:"<<std::endl
               <<"  n: proceed to next card"<<std::endl
               <<"  c: check this card"<<std::endl
               <<"  r: remove all certificates"<<std::endl
               <<"  p: PIN change"<<std::endl
               <<"  i: (re-) import certificates"<<std::endl
               <<"  z: show certificates"<<std::endl
               <<"  a: show authentication certificate"<<std::endl
               <<"  d: show digital signature certificate"<<std::endl
               <<"  q: quit"<<std::endl;
      std::cin>>choice; // small user menu
      try {
        if (choice=="n") { // handled above in the while-loop
        } else if (choice=="c") {
          // run a check of the card status
          TextualCycle check(*card);
          if (check.run())
            std::cout<<"----> SuisseID is fine"<<std::endl;
          else
            std::cout<<"****> SuisseID is bad"<<std::endl;
        } else if (choice=="r") {
          std::cout<<"Not yet implemented."<<std::endl;
        } else if (choice=="p") {
          // change card pins
          std::string oldpin, newpin;
          std::cout<<"Enter Old PIN: ";
          std::cin>>oldpin;
          std::cout<<"Enter New PIN: ";
          std::cin>>newpin;
          if (oldpin.size() && newpin.size())
            (*card)->changePins(newpin, oldpin);
        } else if (choice=="i") {
          // install new certificates - not fully implemented
          TextualCycle check(*card);
          check.installCerts(true);
        } else if (choice=="z") {
          // show all certificates on the card
          for (suisseid::Certificates::iterator cert(certs.begin());
               cert!=certs.end(); ++cert) {
            show(*cert);
          }
        } else if (choice=="a") {
          // show authentication certificate only
          show((*card)->authenticationCertificate());
        } else if (choice=="d") {
          // show authentication certificate only
          show((*card)->digitalSignatureCertificate());
        } else if (choice=="q") {
          // done, user quits
          return 0;
        } else {
          // unknown user command
          std::cout<<"I beg your pardon, Sir?"<<std::endl;
        }
      } catch (const std::exception& x) {
        std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
      }
    } catch (std::exception& x) {
      std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
      choice="n"; // proceed to next card
    }
  }
  return 0;
 } catch (std::exception& x) {
  std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
 }
