/***************************************************************************
                        FLAccessControlLists.cpp
                          -------------------
 begin                : Fri Oct 10 2005
 copyright            : (C) 2004-2005 by InfoSiAL S.L.
 email                : mail@infosial.com
***************************************************************************/
/***************************************************************************
 *   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; version 2 of the License.               *
 ***************************************************************************/
/***************************************************************************
   Este  programa es software libre. Puede redistribuirlo y/o modificarlo
   bajo  los  términos  de  la  Licencia  Pública General de GNU   en  su
   versión 2, publicada  por  la  Free  Software Foundation.
 ***************************************************************************/

#include "FLAccessControl.h"
#include "FLAccessControlFactory.h"
#include "FLAccessControlLists.h"
#include "FLUtil.h"
#include "FLTableMetaData.h"
#include "FLManagerModules.h"
#include "FLApplication.h"
#include "FLSqlQuery.h"
#include "FLSqlDatabase.h"
#include "FLSqlConnections.h"

FLAccessControlLists::FLAccessControlLists() : name_( QString::null ), accessControlList_( 0 ) {}

FLAccessControlLists::~FLAccessControlLists() {
  if ( accessControlList_ ) {
    accessControlList_->clear();
    delete accessControlList_;
  }
}

void FLAccessControlLists::init() {
  init( FLSqlConnections::database()->managerModules()->content( "acl.xml" ) );
}

void FLAccessControlLists::init( const QString & aclXml ) {
  QDomDocument doc( "ACL" );

  if ( accessControlList_ ) {
    accessControlList_->clear();
    delete accessControlList_;
    accessControlList_ = 0;
  }

  if ( !FLUtil::domDocumentSetContent( doc, aclXml ) ) {
#ifdef FL_DEBUG
    qWarning( "FLAccessControlLists : " + QApplication::tr( "Lista de control de acceso vacia o errónea." ) );
#endif
    return ;
  }

  accessControlList_ = new QDict < FLAccessControl >();
  accessControlList_->setAutoDelete( true );

  QDomElement docElem = doc.documentElement();
  QDomNode no = docElem.firstChild();

  while ( !no.isNull() ) {
    QDomElement e = no.toElement();
    if ( !e.isNull() ) {
      if ( e.tagName() == "name" ) {
        name_ = e.text();
        no = no.nextSibling();
        continue;
      }

      FLAccessControl * ac = FLAccessControlFactory::create( e.tagName() );
      if ( ac ) {
        ac->set( &e );
        accessControlList_->replace( ac->type() + "::" + ac->name() + "::" + ac->user(), ac );
        no = no.nextSibling();
        continue;
      }
    }
    no = no.nextSibling();
  }
}

void FLAccessControlLists::process( QObject * obj ) {
  if ( !obj || !accessControlList_ )
    return ;

  if ( accessControlList_->isEmpty() )
    return ;

  QString type = FLAccessControlFactory::type( obj );
  QString name = obj->name();
  QString user = FLSqlConnections::database()->user();

  if ( type.isEmpty() || name.isEmpty() || user.isEmpty() )
    return ;

  QString key = type + "::" + name + "::" + user;
  FLAccessControl * ac = ( *accessControlList_ )[ key ];
  if ( ac )
    ac->processObject( obj );
}

void FLAccessControlLists::installACL( const QString & idacl ) {
  QDomDocument doc( "ACL" );

  QDomElement root = doc.createElement( "ACL" );
  doc.appendChild( root );

  QDomElement name = doc.createElement( "name" );
  root.appendChild( name );
  QDomText n = doc.createTextNode( idacl );
  name.appendChild( n );

  FLSqlQuery q;

  q.setTablesList( "flacs" );
  q.setSelect( "idac,tipo,nombre,iduser,idgroup,degrupo,permiso" );
  q.setFrom( "flacs" );
  q.setWhere( "idacl='" + idacl + "'" );
  q.setOrderBy( "prioridad DESC,tipo" );
  q.setForwardOnly( true );

  if ( q.exec() ) {
    uint step = 0;
    QProgressDialog progress( QApplication::tr( "Instalando control de acceso..." ), 0, q.size(), 0, 0, true );
    progress.setCaption( QApplication::tr( "Instalando ACL" ) );
    progress.setMinimumDuration( 0 );
    progress.setProgress( ++step );
    while ( q.next() ) {
      makeRule( &q, &doc );
      progress.setProgress( ++step );
    }
    FLSqlConnections::database()->managerModules()->setContent( "acl.xml", "sys", doc.toString() );
  }
}

void FLAccessControlLists::makeRule( FLSqlQuery * q, QDomDocument * d ) {
  if ( !q || !d )
    return ;

  if ( q->value( 5 ).toBool() )
    makeRuleGroup( q, d, q->value( 4 ).toString() );
  else
    makeRuleUser( q, d, q->value( 3 ).toString() );
}

void FLAccessControlLists::makeRuleUser( FLSqlQuery * q, QDomDocument * d, const QString & iduser ) {
  if ( iduser.isEmpty() || !q || !d )
    return ;

  FLAccessControl * ac = FLAccessControlFactory::create( q->value( 1 ).toString() );

  if ( ac ) {
    ac->setName( q->value( 2 ).toString() );
    ac->setUser( iduser );
    ac->setPerm( q->value( 6 ).toString() );

    FLSqlQuery qAcos;

    qAcos.setTablesList( "flacos" );
    qAcos.setSelect( "nombre,permiso" );
    qAcos.setFrom( "flacos" );
    qAcos.setWhere( "idac='" + q->value( 0 ).toString() + "'" );
    qAcos.setForwardOnly( true );

    QStringList acos;

    if ( qAcos.exec() ) {
      while ( qAcos.next() ) {
        acos << qAcos.value( 0 ).toString();
        acos << qAcos.value( 1 ).toString();
      }
    }

    ac->setAcos( acos );
    ac->get( d );

    delete ac;
  }
}

void FLAccessControlLists::makeRuleGroup( FLSqlQuery * q, QDomDocument * d, const QString & idgroup ) {
  if ( idgroup.isEmpty() || !q || !d )
    return ;

  FLSqlQuery qU;

  qU.setTablesList( "flusers" );
  qU.setSelect( "iduser" );
  qU.setFrom( "flusers" );
  qU.setWhere( "idgroup='" + idgroup + "'" );
  qU.setForwardOnly( true );

  if ( qU.exec() )
    while ( qU.next() )
      makeRuleUser( q, d, qU.value( 0 ).toString() );
}
