/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2009-08-31
**  Copyright: 2009-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <fcntl.h>
#include <unistd.h>

#include "Trace.h"
#include "Global.h"
#include "CoreApplication.h"
#include "Leds.h"

namespace QGpCoreTools {

/*!
  \class Leds Leds.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

Leds * Leds::_self=0;

static const char * ledPath="/sys/class/leds/alix:";
static const char * ledIndex[]={"1/", "2/", "3/"};

/*!
  Description of constructor still missing
*/
Leds::Leds(QObject * parent)
    : QObject(parent)
{
  TRACE;

  ASSERT(!_self);

  // Test all 3 lights
  if(!test(0) || !test(1) || !test(2)) {
    App::log(tr("no led available\n") );
    // Do not initialize _self, leds are not available
    return;
  }

  _self=this;
  connect(&_timer[0], SIGNAL(timeout()), this, SLOT(execTimer0()));
  connect(&_timer[1], SIGNAL(timeout()), this, SLOT(execTimer1()));
  connect(&_timer[2], SIGNAL(timeout()), this, SLOT(execTimer2()));
  _defaultOn[0]=false;
  _defaultOn[1]=false;
  _defaultOn[2]=false;
}

bool Leds::test(int index)
{
#ifdef Q_OS_LINUX
  std::string p=ledPath;
  p+=ledIndex[index];
  p+="brightness";
  int fd=open(p.data(), O_RDONLY);
  if(fd>0) {
    char state;
    if(read(fd, &state, 1)==1) {
      close(fd);
      return true;
    }
    close(fd);
  }
#else
  Q_UNUSED(index)
#endif
  return false;
}

void Leds::power(int index, bool on)
{
  if(_self) {
    _self->setTrigger(index, "default-on");
    _self->powerInternal(index, on);
  }
}

void Leds::flash(int index, int msec, bool on)
{
  if(_self) {
    QTimer& t=_self->_timer[index];
    _self->_defaultOn[index]=!on;
    t.setInterval(msec);
    t.start();
    _self->setTrigger(index, "default-on");
    power(index, on);
  }
}

void Leds::timer(int index, int msecOn, int msecOff)
{
  if(_self) {
    _self->setTrigger(index, "timer");
    _self->powerInternal(index, true);
    _self->setDelayOn(index, msecOn);
    _self->setDelayOff(index, msecOff);
  }
}

void Leds::setTrigger(int index, const char * type)
{
#ifdef Q_OS_UNIX
  std::string p=ledPath;
  p+=ledIndex[index];
  p+="trigger";
  int fd=open(p.data(), O_WRONLY);
  if(fd>0) {
    int n=strlen(type);
    if(write(fd, type, n)!=n) {
      App::log(tr("setTrigger: error writing to %1\n").arg(p.data()) );
    }
    close(fd);
  }
#else
  Q_UNUSED(index)
  Q_UNUSED(type)
#endif
}

void Leds::powerInternal(int index, bool on)
{
#ifdef Q_OS_UNIX
  std::string p=ledPath;
  p+=ledIndex[index];
  p+="brightness";
  int fd=open(p.data(), O_WRONLY);
  if(fd>0) {
    if(write(fd, on ? "1" : "0", 1)!=1) {
      App::log(tr("power: error writing to %1\n").arg(p.data()) );
    }
    close(fd);
  }
#else
  Q_UNUSED(index)
  Q_UNUSED(on)
#endif
}

void Leds::setDelayOn(int index, int msec)
{
#ifdef Q_OS_UNIX
  std::string p=ledPath;
  p+=ledIndex[index];
  p+="delay_on";
  int fd=open(p.data(), O_WRONLY);
  if(fd>0) {
    char buf[16];
    sprintf(buf, "%i", msec);
    int n=strlen(buf);
    if(write(fd, buf, n)!=n) {
      App::log(tr("setDelayOn: error writing to %1\n").arg(p.data()) );
    }
    close(fd);
  }
#else
  Q_UNUSED(index)
  Q_UNUSED(msec)
#endif
}

void Leds::setDelayOff(int index, int msec)
{
#ifdef Q_OS_UNIX
  std::string p=ledPath;
  p+=ledIndex[index];
  p+="delay_off";
  int fd=open(p.data(), O_WRONLY);
  if(fd>0) {
    char buf[16];
    sprintf(buf, "%i", msec);
    int n=strlen(buf);
    if(write(fd, buf, n)!=n) {
      App::log(tr("setDelayOff: error writing to %1\n").arg(p.data()) );
    }
    close(fd);
  }
#else
  Q_UNUSED(index)
  Q_UNUSED(msec)
#endif
}

void Leds::execTimer0()
{
  Leds::power(0, _defaultOn[0]);
}

void Leds::execTimer1()
{
  Leds::power(1, _defaultOn[1]);
}

void Leds::execTimer2()
{
  Leds::power(2, _defaultOn[2]);
}

} // namespace QGpCoreTools
