<?php
namespace Cadoles\CoreBundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Input\ArrayInput;

use Cadoles\CoreBundle\Entity\User;
use Cadoles\CoreBundle\Entity\Group;
use Cadoles\CoreBundle\Entity\UserGroup;

class ScribeToNinegateCommand extends Command
{
    private $container;
    private $em;
    private $output;
    private $connection;
    private $host;
    private $port;
    private $pwd;
    private $user;
    
    protected function configure()
    {
        $this
            ->setName('Core:ScribeToNinegate')
            ->setDescription('Récupére un annuaire Scribe et le transforme en donnée Ninegate')
            ->setHelp('Récupére un annuaire Scribe et le transforme en donnée Ninegate')
            ->addArgument('host', InputArgument::REQUIRED, 'host du ldap scribe') 
            ->addArgument('pwd', InputArgument::REQUIRED, 'pwd du compte  cn=admin,o=gouv,c=fr') 
        ;
    }

        
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->container    = $this->getApplication()->getKernel()->getContainer();
        $this->em           = $this->container->get('doctrine')->getEntityManager();
        $this->output       = $output;

        // Récupérer les parametres
        $this->host = $input->getArgument('host');
        $this->port = 389;
        $this->pwd  = $input->getArgument('pwd');
        $this->user = "cn=reader,o=gouv,c=fr";
        
        $ldap_basedn        = $this->container->getParameter('ldap_basedn');
        $ldap_username      = $this->container->getParameter('ldap_username');
        $ldap_firstname     = $this->container->getParameter('ldap_firstname');
        $ldap_lastname      = $this->container->getParameter('ldap_lastname');
        $ldap_email         = $this->container->getParameter('ldap_email');
        $ldap_usersadmin    = $this->container->getParameter('ldap_usersadmin');
        $fieldstoread       = array($ldap_username,$ldap_firstname,$ldap_lastname,$ldap_email,"userPassword");

        if(!$this->connect()) {
            $this->writelnred("IMPOSSIBLE DE SE CONNECTER A L'ANNUAIRE SCRIBE");
            return 0;
        }
        
        // On arrive à se connecter à l'annuaire du scribe
        $this->writeln("CONNEXION A L'ANNUAIRE SCRIBE");

        // Attention confirmation
        $this->writeln('');
        $this->writelnred('ATTENTION');
        $this->writelnred('En confirmant vous allez totalement réinitialiser votre Ninegate');
        $helper = $this->getHelper('question');
        $question = new ConfirmationQuestion('Souhaitez-vous poursuivre (yes/no)?', false);
        if (!$helper->ask($input, $output, $question)) {
            return 0;
        }

        $this->writelnred('');
        $this->writelnred('== PURGE');

        $this->writelnred('PURGE DES CONFIG');
        $this->purge('CadolesCoreBundle:Config');
        $this->purge('CadolesCoreBundle:Script');
        $this->purge('CadolesCoreBundle:Statistic');
        $this->purge('CadolesCoreBundle:Whitelist');

        $this->writelnred('PURGE DES ITEMS');
        $this->purge('CadolesPortalBundle:Item');
        $this->purge('CadolesPortalBundle:Itemcategory');

        $this->writelnred('PURGE DES BOOKMARKS');
        $this->purge('CadolesPortalBundle:Bookmark');

        $this->writelnred('PURGE DES ALERTES');
        $this->purge('CadolesPortalBundle:Alert');
        $this->purge('CadolesPortalBundle:Alertcategory');

        $this->writelnred('PURGE DES NOTICE');
        $this->purge('CadolesPortalBundle:Notice');

        $this->writelnred('PURGE DES CALENDAR');
        $this->purge('CadolesPortalBundle:Calendar');

        $this->writelnred('PURGE DES FLUX');
        $this->purge('CadolesPortalBundle:Flux');

        $this->writelnred('PURGE DES BLOG');
        $this->purge('CadolesPortalBundle:Blog');

        $this->writelnred('PURGE DES PROJECT');
        $this->purge('CadolesPortalBundle:Project');

        $this->writelnred('PURGE DES UTILISATEURS');
        $this->purge('CadolesCoreBundle:User');
        
        $this->writelnred('PURGE DES INSCRIPTIONS');
        $this->purge('CadolesCoreBundle:Registration');

        $this->writelnred('PURGE DES GROUPES');
        $this->purge('CadolesCoreBundle:Group');

        $this->writelnred('PURGE DES NIVEAU 02');
        $this->purge('CadolesCoreBundle:Niveau02');

        $this->writelnred('PURGE DES NIVEAU 01');
        $this->purge('CadolesCoreBundle:Niveau01');

        $this->writelnred('PURGE DES PAGES');
        $this->purge('CadolesPortalBundle:Page');

        $this->writelnred('PURGE DES ICONES');
        $this->purge('CadolesPortalBundle:Icon');        
        
        $this->writeln('');

        $this->writelnred('');
        $this->writelnred('== INIT DATA');
        $command = $this->getApplication()->find("Core:InitData");
        $parameter = new ArrayInput([]);
        $command->run($parameter, $output);

        $command = $this->getApplication()->find("Cron:InitData");
        $parameter = new ArrayInput([]);
        $command->run($parameter, $output);

        $command = $this->getApplication()->find("Portal:InitData");
        $parameter = new ArrayInput([]);
        $command->run($parameter, $output);

        $command = $this->getApplication()->find("Core:Script");
        $parameter = new ArrayInput([]);
        $command->run($parameter, $output);


        $this->writelnred('');
        $this->writelnred('== USERS SCRIBE TO USERS NINEGATE');
        $niveau01=$this->em->getRepository('CadolesCoreBundle:Niveau01')->find(-100);
        $niveau01->setSiren("");
        $this->em->persist($niveau01);
        $this->em->flush();  

        $scribeusers = $this->search("(&(uid=*)(mail=*)(objectClass=person)(!(description=Computer)))", $fieldstoread, $ldap_basedn);
        foreach($scribeusers as $scribeuser) {
            if($scribeuser[$ldap_email]=="") {
                $this->writelnred("Compte sans mail = ".$scribeuser[$ldap_username]." ".$scribeuser[$ldap_email]);
                continue;
            }
            $user=$this->em->getRepository('CadolesCoreBundle:User')->findOneBy(array('email' => $scribeuser[$ldap_email]));
            if($user&&$user->getUsername()!=$scribeuser[$ldap_username]) { 
                $this->writelnred("EMAIL en double = ".$scribeuser[$ldap_username]." ".$scribeuser[$ldap_email]);
                continue;
            }


            $this->writeln($scribeuser[$ldap_username]." ".$scribeuser[$ldap_email]);
            $user=$this->em->getRepository('CadolesCoreBundle:User')->findOneBy(array('username' => $scribeuser[$ldap_username]));
            if(!$user) {
                $user = new User();
                $user->setUsername($scribeuser[$ldap_username]);
            }
        
            $user->setLastname($scribeuser[$ldap_lastname]);
            $user->setFirstname($scribeuser[$ldap_firstname]);
            $user->setEmail($scribeuser[$ldap_email]);        
            $user->setNiveau01($niveau01);
            $user->setSiren($niveau01->getSiren());
            $user->setPasswordDirect($scribeuser["userpassword"]);
            $user->setSalt(uniqid(mt_rand(), true));
            $user->setVisible(true);
            $user->setAuthlevel("simple");
            $user->setBelongingpopulation("agent");                

            if(in_array($scribeuser[$ldap_username],$ldap_usersadmin))
                $user->setRole("ROLE_ADMIN");
            else
                $user->setRole("ROLE_USER");

            $this->em->persist($user);
            $this->em->flush();            
        }

        $this->writelnred('');
        $this->writelnred('== USERS SCRIBE TO USERS NINEGATE');
        $scribegroups = $this->search("(objectClass=posixGroup)", ["cn","memberuid"], $ldap_basedn);
        $exludgroupe=["DomainAdmins","DomainUsers","DomainComputers","PrintOperators","eleves","professeurs"];
        foreach($scribegroups as $scribegroup) {
            if(in_array($scribegroup["cn"],$exludgroupe)) continue;

            $this->writeln($scribegroup["cn"]);
            $group=$this->em->getRepository('CadolesCoreBundle:Group')->findOneBy(array('label' => $scribegroup["cn"]));
            if(!$group) {
                $group = new Group();
                $group->setLabel($scribegroup["cn"]);
            }

            $group->setFgcanshare(false);
            $group->setFgcancreatepage(false);
            $group->setFgcancreateblog(false);
            $group->setFgcancreatecalendar(false);
            $group->setFgcancreateproject(false);       
            $group->setFgopen(false);   
            $group->setFgall(false);   
            $group->setFgtemplate(false);   
            $this->em->persist($group);
            $this->em->flush();   

            if(array_key_exists("memberuid",$scribegroup))
            {
                if(!is_array($scribegroup["memberuid"]))
                    $scribegroup["memberuid"] = [ $scribegroup["memberuid"] ];
            }
            else
                $scribegroup["memberuid"] = [];


            foreach($scribegroup["memberuid"] as $scribemember) {
                $user=$this->em->getRepository('CadolesCoreBundle:User')->findOneBy(array('username' => $scribemember));
                if($user) {
                    $member=$this->em->getRepository('CadolesCoreBundle:UserGroup')->findOneBy(array('group' => $group, 'user' => $user));
                    if(!$member) {
                        $member= new UserGroup();
                        $member->setGroup($group);
                        $member->setUser($user);
                        $member->setRolegroup(0);

                        $this->em->persist($member);
                        $this->em->flush();   
                    }  
                }
            }
        }

        return 1;
    }

    private function purge($entityname) {
        // Si on purge les pages il faut d'abord purger les pages qui ne sont pas pagetemplate
        if($entityname=="CadolesPortalBundle:Page") {
            $qb=$this->em->createQueryBuilder();
            $entitys = $qb->select('t')
                   ->from($entityname,'t')
                   ->where($qb->expr()->isNotNull('t.page'))
                   ->getQuery()
                   ->getResult();
            foreach ($entitys as $entity) {
                $this->em->remove($entity);
            }
            $this->em->flush();
        }

        $entitys=$this->em->getRepository($entityname)->findAll();
        foreach ($entitys as $entity) {
            $this->em->remove($entity);
        }
        $this->em->flush();
    }



    private function connect() {
        if($this->connection){
            return $this->connection;
        } else {
            $ldapConn = ldap_connect($this->host, $this->port);
            if($ldapConn){
                ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
                if(ldap_bind( $ldapConn, $this->user, $this->pwd)){
                    $this->connection = $ldapConn;
                    return $this->connection;
                }
            }
        }
    }

    public function search($filter, $attributes = array(), $subBranch = '') {
        $connection = $this->connect();
        $branch = ($subBranch ? $subBranch : $this->baseDN);
        $result = ldap_search($connection, $branch, $filter, $attributes,0,0,0);
        if(!$result) {
            $this->ldapError();
        }
        return $this->resultToArray($result);
    }

    private function resultToArray($result){

        $connection = $this->connect();
        $resultArray = array();

        if($result){
            $entry = ldap_first_entry($connection, $result);
            while ($entry){
                $row = array();
                $attr = ldap_first_attribute($connection, $entry);
                while ($attr){
                    $val = ldap_get_values_len($connection, $entry, $attr);
                    if(array_key_exists('count', $val) AND $val['count'] == 1){
                        $row[strtolower($attr)] = $val[0];
                    } else {
                        $row[strtolower($attr)] = $val;
                    }
                    $attr = ldap_next_attribute($connection, $entry);
                }
                $resultArray[] = $row;
                $entry = ldap_next_entry($connection, $entry);
            }
        }

        return $resultArray;
    }

    public function ldapError(){
        $connection = $this->connect();
        throw new \Exception(
            'Error: ('. ldap_errno($connection) .') '. ldap_error($connection)
        );
    }    

    private function writelnred($string) { 
        $this->output->writeln('<fg=red>'.$string.'</>');
    }
    private function writeln($string) { 
        $this->output->writeln($string);
    }     
}
