<?php
/*
 * This file is part of Phraseanet
 *
 * (c) 2005-2016 Alchemy
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Alchemy\Phrasea\Controller\Admin;

use Alchemy\Phrasea\Application\Helper\NotifierAware;
use Alchemy\Phrasea\Application\Helper\UserQueryAware;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Response\CSVFileResponse;
use Alchemy\Phrasea\Helper\User as UserHelper;
use Alchemy\Phrasea\Model\Entities\AuthFailure;
use Alchemy\Phrasea\Model\Entities\Feed;
use Alchemy\Phrasea\Model\Entities\FtpCredential;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Entities\WebhookEvent;
use Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator;
use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
use Alchemy\Phrasea\Model\NativeQueryProvider;
use Alchemy\Phrasea\Model\Repositories\FeedEntryRepository;
use Alchemy\Phrasea\Model\Repositories\FeedRepository;
use Alchemy\Phrasea\Model\Repositories\RegistrationRepository;
use Alchemy\Phrasea\Model\Repositories\UserRepository;
use Alchemy\Phrasea\Notification\Mail\MailSuccessEmailUpdate;
use Alchemy\Phrasea\Notification\Receiver;
use Doctrine\ORM\EntityManager;
use Goodby\CSV\Export\Protocol\ExporterInterface;
use Goodby\CSV\Import\Standard\Interpreter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class UserController extends Controller
{
    use NotifierAware;
    use UserQueryAware;

    public function editRightsAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);

        // use to have the previous page
        $params  = $request->request->all();

        return $this->render('admin/editusers.html.twig',
            array_merge($rights->get_user_records_rights(),
                $rights->getFeeds(),
                $rights->getBasketElements(),
                $rights->get_users_rights(),
                ['previousParam' => $params]
            )
        );
    }

    public function listRecordAcl(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        $expireRight = ($request->query->get('expiredRight') == 1) ? true : false ;
        $results = $rights->get_user_records_rights(
            $request->query->get('userId'),
            $request->query->get('databoxId'),
            $request->query->get('recordId'),
            $request->query->get('type'),
            $expireRight
        );

        return $this->app->json([
            'content'       => $this->render('admin/user/records_list.html.twig', ['records_acl' => $results['records_acl']]),
            'total_count'   => $results['total_count'],
            'total_result'  => count($results['records_acl'])
        ]);
    }

    public function deleteFeedEntry(Request $request)
    {
        /** @var EntityManager $manager */
        $manager = $this->app['orm.em'];
        /** @var FeedEntryRepository $feedEntryRepo */
        $feedEntryRepo = $this->app['repo.feed-entries'];

        /** @var Feed|null $feed */
        $feedEntry = $feedEntryRepo->find($request->request->get('feedEntryId'));

        if ($feedEntry == null) {
            return $this->app->json(['success'  => false, 'message' => 'publication not found']);
        }

        $manager->remove($feedEntry);
        $manager->flush();

        return $this->app->json(['success'  => true]);
    }

    public function listFeedEntry(Request $request)
    {
        /** @var UserRepository $userRepo */
        $userRepo = $this->app['repo.users'];
        $user = $userRepo->find($request->query->get('userId'));

        // when not expand
        if ($request->query->get('feedId') == null) {
            return $this->app->json(['content' => '']);
        }

        /** @var FeedRepository $feedsRepository */
        $feedsRepository = $this->app['repo.feeds'];
        /** @var Feed|null $feed */
        $feed = $feedsRepository->find($request->query->get('feedId'));

        if ($feed == null || $user == null) {
            return $this->app->json(['content' => 'Give feed_id or user_id']);
        } else {
            /** @var FeedEntryRepository $feedEntryRepo */
            $feedEntryRepo = $this->app['repo.feed-entries'];
            $feedEntryRepo->getByUserAndFeed($user, $feed);

            return $this->app->json(['content' => $this->render('admin/user/records_list.html.twig', [
                'feed_entries' => $feedEntryRepo->getByUserAndFeed($user, $feed)
                ]),
                'feed_entries_count' => $feedEntryRepo->getByUserAndFeed($user, $feed, true)
            ]);
        }
    }

    public function listRecordBasket(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        $results = $rights->getBasketElements($request->query->get('userId'), $request->query->get('databoxId'), $request->query->get('recordId'));

        return $this->app->json([
            'content'       => $this->render('admin/user/records_list.html.twig', ['basket_elements' => $results['basket_elements']]),
            'total_count'   => $results['basket_elements_count'],
            'total_result'  => count($results['basket_elements'])
        ]);
    }

    public function resetRightsAction(Request $request)
    {
        try {
            $data = ['error' => false];

            $helper = $this->getUserEditHelper($request);
            $helper->resetRights();
        } catch (\Exception $e) {
            $data['error'] = true;
            $data['message'] = $e->getMessage();
        }

        return $this->app->json($data);
    }

    public function deleteUserAction(Request $request)
    {
        $module = $this->getUserEditHelper($request);
        $module->delete_users();

        return $this->app->redirectPath('admin_users_search');
    }

    public function resetAuthFailureAction(Request $request)
    {
        $this->app['auth.native.failure-manager']->resetLockedFailureByUsername($request->request->get('username'));

        $failures = $this->app['repo.auth-failures']->findBy(['username' => $request->request->get('username'), 'locked' => false], ['created' => 'desc']);

        $failuresTable = [];

        foreach ($failures as $key => $failure) {
            /** @var AuthFailure $failure */
            $failuresTable[$key]['username'] = $failure->getUsername();
            $failuresTable[$key]['ip'] = $failure->getIp();
            $failuresTable[$key]['created'] = $failure->getCreated()->format('Y-m-d H:i:s');
        }

        return $this->app->json([
            'success' => true,
            'authFailureUnlocked' => $failuresTable
        ]);
    }

    public function changeMailLockedAction(Request $request)
    {
        $helper = $this->getUserManageHelper($request);
        $helper->setMailLocked();

        return $this->app->json(['success' => true]);
    }

    public function changeCanRenewPasswordAction(Request $request)
    {
        $helper = $this->getUserManageHelper($request);
        $helper->setCanRenewPassword();

        return $this->app->json(['success' => true]);
    }

    public function applyRightsAction(Request $request)
    {
        $data = ['error' => true];

        try {
            $rights = $this->getUserEditHelper($request);

            $resetBeforeApply = (bool) $request->request->get('reset_before_apply', false);
            if (!$resetBeforeApply) {
                $rights->apply_rights();
            }

            if ($request->request->get('template')) {
                if ($resetBeforeApply) {
                    $rights->resetRights();
                }
                $rights->apply_template();
            }

            $rights->apply_infos();

            $data = ['error' => false];
        } catch (\Exception $e) {
            $data['message'] = $e->getMessage();
        }

        return $this->app->json($data);
    }

    public function editQuotasRightsAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        return $this->render('admin/editusers_quotas.html.twig', $rights->get_quotas());
    }

    public function applyQuotasAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        $rights->apply_quotas();

        return $this->app->json(['message' => '', 'error' => false]);
    }

    public function editTimeLimitAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);

        return $this->render('admin/editusers_timelimit.html.twig', $rights->get_time());
    }

    public function editTimeLimitSbasAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);

        return $this->render('admin/editusers_timelimit_sbas.html.twig', $rights->get_time_sbas());
    }

    public function applyTimeAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        $rights->apply_time();

        return $this->app->json(['message' => '', 'error' => false]);
    }

    public function editMasksAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);

        return $this->render('admin/editusers_masks.html.twig', $rights->get_masks());
    }

    public function applyMasksAction(Request $request)
    {
        $rights = $this->getUserEditHelper($request);
        $rights->apply_masks();

        return $this->app->json(['message' => '', 'error' => false]);
    }

    public function searchAction(Request $request)
    {
        // used for back button on user edit
        $previousSelectedUsers = explode(';', $request->request->get('users'));

        return $this->render('admin/users.html.twig', array_merge($this->getUserManageHelper($request)->search(), ['previousSelectedUsers' => $previousSelectedUsers]));
    }

    public function searchExportAction(Request $request)
    {
        $users = $this->getUserManageHelper($request);
        $userTable = [
            [
                'ID',
                'Login',
                'Last Name',
                'First Name',
                'E-Mail',
                'Created',
                'Updated',
                'Address',
                'City',
                'Zip',
                'Country',
                'Phone',
                'Fax',
                'Job',
                'Company',
                'Position',
                'Last Connection'
            ]
        ];

        foreach ($users->export() as $user) {
            $userTable[] = [
                $user->getId(),
                $user->getLogin(),
                $user->getLastName(),
                $user->getFirstName(),
                $user->getEmail(),
                $user->getCreated()->format(DATE_ATOM),
                $user->getUpdated()->format(DATE_ATOM),
                $user->getAddress(),
                $user->getCity(),
                $user->getZipCode(),
                $user->getCountry(),
                $user->getPhone(),
                $user->getFax(),
                $user->getJob(),
                $user->getCompany(),
                $user->getActivity(),
                $this->getUserLastConnection($user)
            ];
        }

        $filename = sprintf('user_export_%s.csv', date('Ymd'));
        $exporter = $this->getCsvExporter();

        return new CSVFileResponse($filename, function () use ($exporter, $userTable) {
            $exporter->export('php://output', $userTable);
        });
    }

    public function applyTemplateAction(Request $request)
    {
        $users = $this->getUserEditHelper($request);
        if ($request->request->get('reset_before_apply')) {
            $users->resetRights();
        }
        $users->apply_template();

        return $this->app->redirectPath('admin_users_search');
    }

    public function typeAheadSearchAction(Request $request)
    {
        $user_query = $this->createUserQuery();

        $like_value = $request->query->get('term');
        $rights = $request->query->get('filter_rights') ? : [];
        $have_right = $request->query->get('have_right') ? : [];
        $have_not_right = $request->query->get('have_not_right') ? : [];
        $on_base = $request->query->get('on_base') ? : [];

        $eligible_users = $user_query
            ->on_sbas_where_i_am($this->getAclForConnectedUser(), $rights)
            ->like(\User_Query::LIKE_EMAIL, $like_value)
            ->like(\User_Query::LIKE_FIRSTNAME, $like_value)
            ->like(\User_Query::LIKE_LASTNAME, $like_value)
            ->like(\User_Query::LIKE_LOGIN, $like_value)
            ->like_match(\User_Query::LIKE_MATCH_OR)
            ->who_have_right($have_right)
            ->who_have_not_right($have_not_right)
            ->on_base_ids($on_base)
            ->include_templates(true)
            ->execute()
            ->get_results();

        $data = [];
        foreach ($eligible_users as $user) {
            $data[] = [
                'email' => $user->getEmail() ? : '',
                'login' => $user->getLogin() ? : '',
                'name'  => $user->getDisplayName(),
                'id'    => $user->getId(),
            ];
        }

        return $this->app->json($data);
    }

    public function createAction(Request $request)
    {
        $data = ['error'   => false, 'message' => '', 'data'    => null];
        try {
            $module = $this->getUserManageHelper($request);
            if ($request->request->get('template') == '1') {
                $user = $module->createTemplate();
            } else {
                $user = $module->createNewUser();
            }
            if (!$user instanceof User) {
                throw new \Exception('Unknown error');
            }

            $data['data'] = $user->getId();
        } catch (\Exception $e) {
            $data['error'] = true;
            if ($request->request->get('template') == '1') {
                $data['message'] = $this->app->trans('Unable to create template, the name is already used.');
            } else {
                $data['message'] = $this->app->trans('Unable to create the user.');
            }
        }

        return $this->app->json($data);
    }

    public function exportAction(Request $request)
    {
        $user_query = $this->createUserQuery();

        $like_value = $request->request->get('like_value');
        $like_field = $request->request->get('like_field');
        $on_base = $request->request->get('base_id') ? : null;
        $on_sbas = $request->request->get('sbas_id') ? : null;

        $eligible_users = $user_query->on_bases_where_i_am($this->getAclForConnectedUser(), [\ACL::CANADMIN])
            ->like($like_field, $like_value)
            ->on_base_ids($on_base)
            ->on_sbas_ids($on_sbas);

        $offset = 0;
        $buffer = [];
        $buffer[] = [
            'ID',
            'Login',
            $this->app->trans('admin::compte-utilisateur nom'),
            $this->app->trans('admin::compte-utilisateur prenom'),
            $this->app->trans('admin::compte-utilisateur email'),
            'CreationDate',
            'ModificationDate',
            $this->app->trans('admin::compte-utilisateur adresse'),
            $this->app->trans('admin::compte-utilisateur ville'),
            $this->app->trans('admin::compte-utilisateur code postal'),
            $this->app->trans('admin::compte-utilisateur pays'),
            $this->app->trans('admin::compte-utilisateur telephone'),
            $this->app->trans('admin::compte-utilisateur fax'),
            $this->app->trans('admin::compte-utilisateur poste'),
            $this->app->trans('admin::compte-utilisateur societe'),
            $this->app->trans('admin::compte-utilisateur activite'),
        ];
        do {
            $eligible_users->limit($offset, 20);
            $offset += 20;

            $results = $eligible_users->execute()->get_results();

            foreach ($results as $user) {
                $buffer[] = [
                    $user->getId(),
                    $user->getLogin(),
                    $user->getLastName(),
                    $user->getFirstName(),
                    $user->getEmail(),
                    $this->app['date-formatter']->format_mysql($user->getCreated()),
                    $this->app['date-formatter']->format_mysql($user->getUpdated()),
                    $user->getAddress(),
                    $user->getCity(),
                    $user->getZipCode(),
                    $user->getCountry(),
                    $user->getPhone(),
                    $user->getFax(),
                    $user->getJob(),
                    $user->getCompany(),
                    $user->getActivity(),
                ];
            }
        } while (count($results) > 0);

        $filename = sprintf('user_export_%s.csv', date('Ymd'));
        $exporter = $this->getCsvExporter();
        return new CSVFileResponse($filename, function () use ($exporter, $buffer) {
            $exporter->export('php://output', $buffer);
        });
    }

    public function displayRegistrationsAction()
    {
        $this->getRegistrationManipulator()->deleteOldRegistrations();

        /** @var UserRepository $userRepository */
        $userRepository = $this->app['repo.users'];
        $authenticatedUser = $this->getAuthenticatedUser();
        $models = $userRepository->findTemplateOwner($authenticatedUser);

        $userRegistrations = [];
        /** @var RegistrationRepository $registrationRepository */
        $registrationRepository = $this->app['repo.registrations'];
        $collections = $this->getAclForConnectedUser()->get_granted_base([\ACL::CANADMIN]);
        $authenticatedUserId = $authenticatedUser->getId();
        foreach ($registrationRepository->getPendingRegistrations($collections) as $registration) {
            $user = $registration->getUser();
            $userId = $user->getId();
            // Can not handle self registration.
            if ($authenticatedUserId == $userId) {
                continue;
            }
            if (!isset($userRegistrations[$userId])) {
                $userRegistrations[$userId] = ['user' => $user, 'registrations' => []];
            }
            $userRegistrations[$userId]['registrations'][$registration->getBaseid()] = $registration;
        }

        return $this->render('admin/user/registrations.html.twig', [
            'user_registrations' => $userRegistrations,
            'models' => $models,
        ]);
    }

    public function deleteUserRegistrationAction(Request $request)
    {
        /** @var EntityManager $manager */
        $manager = $this->app['orm.em'];
        /** @var RegistrationRepository $registrationRepository */
        $registrationRepository = $this->app['repo.registrations'];

        /** @var UserRepository $userRepository */
        $userRepository = $this->app['repo.users'];
        $registrations = $registrationRepository->findBy(['user' => $userRepository->find($request->request->get('userId'))]);

        if (empty($registrations)) {
            return $this->app->json(['success'  => false, 'message' => 'registration not found']);
        }

        foreach ($registrations as $registration) {
            $manager->remove($registration);
        }

        $manager->flush();

        return $this->app->json(['success'  => true]);
    }

    public function displayAuthFailureAction(Request $request)
    {
        return $this->render('admin/auth-failure.html.twig', [
        ]);
    }

    public function deleteAuthFailureAction(Request $request)
    {
        if ($this->getAuthenticatedUser()->isAdmin()) {
            $this->app['auth.native.failure-manager']->removeFailureById($request->request->get('failureId'));
        }

        return $this->render('admin/auth-failure.html.twig', []);
    }

    public function submitRegistrationAction(Request $request)
    {
        $templates = $this->normalizeTemplateArray($request->request->get('template', []));
        $deny = $this->normalizeDenyArray($request->request->get('deny', []), $templates);

        $accepts = $request->request->get('accept', []);
        $accept = $options = [];
        foreach ($accepts as $acc) {
            $acc = explode('_', $acc);
            if (count($acc) == 2 && !isset($templates[$acc[0]])) {
                $accept[$acc[0]][$acc[1]] = $acc[1];
                $options[$acc[0]][$acc[1]] = ['HD' => false, 'WM' => false];
            }
        }

        foreach ($request->request->get('accept_hd', []) as $accHD) {
            $accHD = explode('_', $accHD);
            if (count($accHD) == 2 && isset($accept[$accHD[0]]) && isset($options[$accHD[0]][$accHD[1]])) {
                $options[$accHD[0]][$accHD[1]]['HD'] = true;
            }
        }

        foreach ($request->request->get('watermark', []) as $wm) {
            $wm = explode('_', $wm);
            if (count($wm) == 2 && isset($accept[$wm[0]]) && isset($options[$wm[0]][$wm[1]])) {
                $options[$wm[0]][$wm[1]]['WM'] = true;
            }
        }

        $registrationManipulator = $this->getRegistrationManipulator();
        if (count($templates) > 0 || count($deny) > 0 || count($accept) > 0) {
            $cacheToUpdate = $done = [];

            /** @var UserRepository $userRepository */
            $userRepository = $this->app['repo.users'];
            $searchedUserIds = array_unique(array_merge(
                array_keys($templates),
                array_keys($deny),
                array_keys($accept)
            ));
            // Load all user entities needed afterwards
            $userRepository->findBy(['id' => $searchedUserIds]);
            foreach ($templates as $usr => $template_id) {
                /** @var User $user */
                $user = $userRepository->find($usr);
                if (null === $user) {
                    $this->app->abort(400, sprintf("User with id % in provided in 'template' request variable could not be found", $usr));
                }
                $cacheToUpdate[$usr] = $user;

                /** @var User $user_template */
                $user_template = $userRepository->find($template_id);
                $collections = $this->getAclForUser($user_template)->get_granted_base();
                $baseIds = array_keys($collections);

                $this->getAclForUser($user)->apply_model($user_template, $baseIds);

                foreach ($collections as $collection) {
                    $done[$usr][$collection->get_base_id()] = true;
                }

                $registrationManipulator->deleteUserRegistrations($user, $collections);
            }

            /** @var RegistrationRepository $registrationRepository */
            $registrationRepository = $this->app['repo.registrations'];
            foreach ($deny as $usr => $bases) {
                /** @var User $user */
                $user = $userRepository->find($usr);
                if (null === $user) {
                    $this->app->abort(400, sprintf("User with id % in provided in 'deny' request variable could not be found", $usr));
                }
                $cacheToUpdate[$usr] = $user;
                foreach (
                    $registrationRepository->getUserRegistrations(
                    $user,
                    array_map(function ($baseId) {
                        return \collection::getByBaseId($this->app, $baseId);
                    }, $bases)
                ) as $registration) {
                    $registrationManipulator->rejectRegistration($registration);
                    $done[$usr][$registration->getBaseId()] = false;
                }
            }

            foreach ($accept as $usr => $bases) {
                /** @var User $user */
                $user = $userRepository->find($usr);
                if (null === $user) {
                    $this->app->abort(400, sprintf("User with id % in provided in 'accept' request variable could not be found", $usr));
                }
                $cacheToUpdate[$usr] = $user;
                foreach ($registrationRepository->getUserRegistrations(
                    $user,
                    array_map(function ($baseId) {
                        return \collection::getByBaseId($this->app, $baseId);
                    }, $bases)
                ) as $registration) {
                    $done[$usr][$registration->getBaseId()] = true;
                    $registrationManipulator->acceptRegistration(
                        $registration,
                        $options[$usr][$registration->getBaseId()]['HD'],
                        $options[$usr][$registration->getBaseId()]['WM']
                    );
                }
            }

            array_walk($cacheToUpdate, function (User $user) {
                $this->getAclForUser($user)->delete_data_from_cache();
            });
            unset ($cacheToUpdate);

            foreach ($done as $usr => $bases) {
                $user = $userRepository->find($usr);
                $acceptColl = $denyColl = [];

                $hookName = WebhookEvent::USER_REGISTRATION_REJECTED;
                $hookType = WebhookEvent::USER_REGISTRATION_TYPE;
                $hookData = [
                    'user_id' => $user->getId(),
                    'granted' => [],
                    'rejected' => []
                ];

                foreach ($bases as $bas => $isok) {
                    $collection = \collection::getByBaseId($this->app, $bas);
                    $label = $collection->get_label($this->app['locale']);

                    if ($isok) {
                        $acceptColl[] = $label;
                        $hookData['granted'][$bas] = $label;
                        $hookName = WebhookEvent::USER_REGISTRATION_GRANTED;
                    } else {
                        $denyColl[] = $label;
                        $hookData['rejected'][$bas] = $label;
                    }

                    $this->app['manipulator.webhook-event']->create($hookName, $hookType, $hookData, [$bas]);
                }

                if ($user->hasMailNotificationsActivated() && (0 !== count($acceptColl) || 0 !== count($denyColl))) {
                    $message = '';
                    if (0 !== count($acceptColl)) {
                        $message .= "\n" . $this->app->trans('login::register:email: Vous avez ete accepte sur les collections suivantes : ') . implode(', ', $acceptColl). "\n";
                    }
                    if (0 !== count($denyColl)) {
                        $message .= "\n" . $this->app->trans('login::register:email: Vous avez ete refuse sur les collections suivantes : ') . implode(', ', $denyColl) . "\n";
                    }

                    $receiver = new Receiver(null, $user->getEmail());
                    $mail = MailSuccessEmailUpdate::create($this->app, $receiver, null, $message);

                    if (($locale = $user->getLocale()) != null) {
                        $mail->setLocale($locale);
                    }

                    $this->deliver($mail);
                }
            }
        }

        return $this->app->redirectPath('users_display_registrations', ['success' => 1]);
    }

    public function displayImportFileAction()
    {
        return $this->render('admin/user/import/file.html.twig');
    }
    
    public function submitImportFileAction(Request $request)
    {
        if ((null === $file = $request->files->get('files')) || !$file->isValid()) {
            return $this->app->redirectPath('users_display_import_file', ['error' => 'file-invalid']);
        }

        $equivalenceToMysqlField = $this->getEquivalenceToMysqlField();
        $loginDefined = $pwdDefined = $mailDefined = false;
        $loginNew = [];
        $out = [
            'ignored_row' => [],
            'errors' => []
        ];
        $nbUsrToAdd = 0;

        $lines = [];
        /** @var Interpreter $interpreter */
        $interpreter = $this->app['csv.interpreter'];
        $interpreter->addObserver(function (array $row) use (&$lines) {
            $lines[] = $row;
        });
        $this->app['csv.lexer']->parse($file->getPathname(), $interpreter);

        $roughColumns = array_shift($lines);

        $columnsSanitized = array_map(function ($columnName) {
            return trim(mb_strtolower($columnName));
        }, $roughColumns);

        $columns = array_filter($columnsSanitized, function ($columnName) use (&$out, $equivalenceToMysqlField) {
            if (!isset($equivalenceToMysqlField[$columnName])) {
                $out['ignored_row'][] = $columnName;

                return false;
            }

            return true;
        });

        foreach ($columns as $columnName) {
            if ($equivalenceToMysqlField[$columnName] === 'usr_login') {
                $loginDefined = true;
            }

            if (($equivalenceToMysqlField[$columnName]) === 'usr_password') {
                $pwdDefined = true;
            }

            if (($equivalenceToMysqlField[$columnName]) === 'usr_mail') {
                $mailDefined = true;
            }
        }

        if (!$loginDefined) {
            return $this->app->redirectPath('users_display_import_file', ['error' => 'row-login']);
        }

        if (!$pwdDefined) {
            return $this->app->redirectPath('users_display_import_file', ['error' => 'row-pwd']);
        }

        if (!$mailDefined) {
            return $this->app->redirectPath('users_display_import_file', ['error' => 'row-mail']);
        }

        /** @var UserRepository $userRepository */
        $userRepository = $this->app['repo.users'];
        foreach ($lines as $nbLine => $line) {
            $loginValid = false;
            $pwdValid = false;
            $mailValid = false;

            foreach ($columns as $nbCol => $colName) {
                if (!isset($equivalenceToMysqlField[$colName])) {
                    unset($lines[$nbCol]);
                    continue;
                }

                $sqlField = $equivalenceToMysqlField[$colName];
                $value = $line[$nbCol];

                if ($sqlField === 'usr_login') {
                    $loginToAdd = $value;
                    if ($loginToAdd === "") {
                        $out['errors'][] = $this->app->trans("Login line %line% is empty", ['%line%' => $nbLine + 1]);
                    } elseif (in_array($loginToAdd, $loginNew)) {
                        $out['errors'][] = $this->app->trans(
                            "Login %login% is already defined in the file at line %line%",
                            ['%login%' => $loginToAdd, '%line%' => $nbLine]
                        );
                    } else {
                        if (null !== $userRepository->findByLogin($loginToAdd)) {
                            $out['errors'][] = $this->app->trans(
                                "Login %login% already exists in database",
                                ['%login%' => $loginToAdd]
                            );
                        } else {
                            $loginValid = true;
                        }
                    }
                }

                if ($loginValid && $sqlField === 'usr_mail') {
                    $mailToAdd = $value;

                    if ($mailToAdd === "") {
                        $out['errors'][] = $this->app->trans("Mail line %line% is empty", ['%line%' => $nbLine + 1]);
                    } elseif (null !== $userRepository->findByEmail($mailToAdd)) {
                        $out['errors'][] = $this->app->trans(
                            "Email '%email%' for login '%login%' already exists in database",
                            ['%email%' => $mailToAdd, '%login%' => $loginToAdd]
                        );
                    } else {
                        $mailValid = true;
                    }
                }

                if ($sqlField === 'usr_password') {
                    $passwordToVerif = $value;

                    if ($passwordToVerif === "") {
                        $out['errors'][] = $this->app->trans("Password is empty at line %line%", ['%line%' => $nbLine]);
                    } else {
                        $pwdValid = true;
                    }
                }
            }

            if ($loginValid && $pwdValid && $mailValid) {
                $loginNew[] = $loginToAdd;
                $nbUsrToAdd++;
            }
        }

        if (count($out['errors']) > 0 && $nbUsrToAdd === 0) {
            return $this->render('admin/user/import/file.html.twig', [
                'errors' => $out['errors']
            ]);
        }

        if ($nbUsrToAdd === 0) {
            return $this->app->redirectPath('users_display_import_file', [
                'error' => 'no-user'
            ]);
        }

        $basList = array_keys($this->getAclForConnectedUser()->get_granted_base([\ACL::COLL_MANAGE]));
        /** @var NativeQueryProvider $query */
        $query = $this->app['orm.em.native-query'];
        $models = $query->getModelForUser($this->getAuthenticatedUser(), $basList);

        return $this->render('/admin/user/import/view.html.twig', [
            'nb_user_to_add'   => $nbUsrToAdd,
            'models'           => $models,
            'lines_serialized' => serialize($lines),
            'columns_serialized' => serialize($columns),
            'errors' => $out['errors']
        ]);
    }

    public function submitImportAction(Request $request)
    {
        $nbCreation = 0;

        if ((null === $serializedColumns = $request->request->get('sr_columns')) || ('' === $serializedColumns)) {
            $this->app->abort(400);
        }

        if ((null === $serializedLines = $request->request->get('sr_lines')) || ('' === $serializedLines)) {
            $this->app->abort(400);
        }

        if (null === $model = $request->request->get("modelToApply")) {
            $this->app->abort(400);
        }

        $lines = unserialize($serializedLines);
        $columns = unserialize($serializedColumns);

        $equivalenceToMysqlField = $this->getEquivalenceToMysqlField();

        foreach ($lines as $nbLine => $line) {
            $curUser = [];
            foreach ($columns as $nbCol => $colName) {
                if (!isset($equivalenceToMysqlField[$colName]) || !isset($line[$nbCol])) {
                    continue;
                }

                $sqlField = $equivalenceToMysqlField[$colName];
                $value = trim($line[$nbCol]);

                if ($sqlField === "usr_sexe") {
                    switch ($value) {
                        case "Mlle":
                        case "Mlle.":
                        case "mlle":
                        case "Miss":
                        case "miss":
                        case "0":
                            $curUser[$sqlField] = 0;
                            break;

                        case "Mme":
                        case "Madame":
                        case "Ms":
                        case "Ms.":
                        case "1":
                            $curUser[$sqlField] = 1;
                            break;

                        case "M":
                        case "M.":
                        case "Mr":
                        case "Mr.":
                        case "Monsieur":
                        case "Mister":
                        case "2":
                            $curUser[$sqlField] =  2;
                            break;
                    }
                } else {
                    $curUser[$sqlField] = $value;
                }
            }

            /** @var UserRepository $userRepository */
            $userRepository = $this->app['repo.users'];
            /** @var UserManipulator $userManipulator */
            $userManipulator = $this->app['manipulator.user'];
            if (isset($curUser['usr_login']) && trim($curUser['usr_login']) !== ''
                && isset($curUser['usr_password']) && trim($curUser['usr_password']) !== ''
                && isset($curUser['usr_mail']) && trim($curUser['usr_mail']) !== '') {
                if (null === $userRepository->findByLogin($curUser['usr_login'])
                    && null === $userRepository->findByEmail($curUser['usr_mail'])) {

                    $newUser = $userManipulator
                        ->createUser($curUser['usr_login'], $curUser['usr_password'], $curUser['usr_mail']);

                    $ftpCredential = new FtpCredential();
                    $ftpCredential->setUser($newUser);

                    if (isset($curUser['activeFTP'])) {
                        $ftpCredential->setActive((int) $curUser['activeFTP']);
                    }
                    if (isset($curUser['addrFTP'])) {
                        $ftpCredential->setAddress((string) $curUser['addrFTP']);
                    }
                    if (isset($curUser['passifFTP'])) {
                        $ftpCredential->setPassive((int) $curUser['passifFTP']);
                    }
                    if (isset($curUser['destFTP'])) {
                        $ftpCredential->setReceptionFolder($curUser['destFTP']);
                    }
                    if (isset($curUser['prefixFTPfolder'])) {
                        $ftpCredential->setRepositoryPrefixName($curUser['prefixFTPfolder']);
                    }
                    if (isset($curUser['usr_prenom'])) {
                        $newUser->setFirstName($curUser['usr_prenom']);
                    }
                    if (isset($curUser['usr_nom'])) {
                        $newUser->setLastName($curUser['usr_nom']);
                    }
                    if (isset($curUser['adresse'])) {
                        $newUser->setAddress($curUser['adresse']);
                    }
                    if (isset($curUser['cpostal'])) {
                        $newUser->setZipCode($curUser['cpostal']);
                    }
                    if (isset($curUser['usr_sexe'])) {
                        $newUser->setGender((int) ($curUser['usr_sexe']));
                    }
                    if (isset($curUser['tel'])) {
                        $newUser->setPhone($curUser['tel']);
                    }
                    if (isset($curUser['fax'])) {
                        $newUser->setFax($curUser['fax']);
                    }
                    if (isset($curUser['activite'])) {
                        $newUser->setActivity($curUser['activite']);
                    }
                    if (isset($curUser['fonction'])) {
                        $newUser->setJob($curUser['fonction']);
                    }
                    if (isset($curUser['societe'])) {
                        $newUser->setCompany($curUser['societe']);
                    }

                    $this->getAclForUser($newUser)->apply_model(
                        $userRepository->find($model),
                        array_keys($this->getAclForConnectedUser()->get_granted_base([\ACL::COLL_MANAGE]))
                    );

                    $nbCreation++;
                }
            }
        }

        return $this->app->redirectPath('admin_users_search', ['user-updated' => $nbCreation]);
    }

    public function importCsvExampleAction()
    {
        $filename = $this->app['root.path'] . '/resources/examples/example_import_users.csv';
        $contentType = 'text/csv';
        return $this->returnExampleFile($filename, $contentType);
    }

    public function importRtfExampleAction()
    {
        $filename = $this->app['root.path'] . '/resources/examples/fields.rtf';
        $contentType = 'text/rtf';
        return $this->returnExampleFile($filename, $contentType);
    }

    public function getEquivalenceToMysqlField()
    {
        return [
            'civilite'                      => 'usr_sexe',
            'gender'                        => 'usr_sexe',
            'usr_sexe'                      => 'usr_sexe',
            'nom'                           => 'usr_nom',
            'name'                          => 'usr_nom',
            'last name'                     => 'usr_nom',
            'last_name'                     => 'usr_nom',
            'usr_nom'                       => 'usr_nom',
            'first name'                    => 'usr_prenom',
            'first_name'                    => 'usr_prenom',
            'prenom'                        => 'usr_prenom',
            'usr_prenom'                    => 'usr_prenom',
            'identifiant'                   => 'usr_login',
            'login'                         => 'usr_login',
            'usr_login'                     => 'usr_login',
            'usr_password'                  => 'usr_password',
            'password'                      => 'usr_password',
            'mot de passe'                  => 'usr_password',
            'usr_mail'                      => 'usr_mail',
            'email'                         => 'usr_mail',
            'mail'                          => 'usr_mail',
            'adresse'                       => 'adresse',
            'adress'                        => 'adresse',
            'address'                       => 'adresse',
            'ville'                         => 'ville',
            'city'                          => 'ville',
            'zip'                           => 'cpostal',
            'zipcode'                       => 'cpostal',
            'zip_code'                      => 'cpostal',
            'cpostal'                       => 'cpostal',
            'cp'                            => 'cpostal',
            'code_postal'                   => 'cpostal',
            'tel'                           => 'tel',
            'telephone'                     => 'tel',
            'phone'                         => 'tel',
            'fax'                           => 'fax',
            'job'                           => 'fonction',
            'fonction'                      => 'fonction',
            'function'                      => 'fonction',
            'societe'                       => 'societe',
            'company'                       => 'societe',
            'activity'                      => 'activite',
            'activite'                      => 'activite',
            'pays'                          => 'pays',
            'country'                       => 'pays',
            'ftp_active'                    => 'activeFTP',
            'compte_ftp_actif'              => 'activeFTP',
            'ftpactive'                     => 'activeFTP',
            'activeftp'                     => 'activeFTP',
            'ftp_adress'                    => 'addrFTP',
            'adresse_du_serveur_ftp'        => 'addrFTP',
            'addrftp'                       => 'addrFTP',
            'ftpaddr'                       => 'addrFTP',
            'loginftp'                      => 'loginFTP',
            'ftplogin'                      => 'loginFTP',
            'ftppwd'                        => 'pwdFTP',
            'pwdftp'                        => 'pwdFTP',
            'destftp'                       => 'destFTP',
            'destination_folder'            => 'destFTP',
            'dossier_de_destination'        => 'destFTP',
            'passive_mode'                  => 'passifFTP',
            'mode_passif'                   => 'passifFTP',
            'passifftp'                     => 'passifFTP',
            'retry'                         => 'retryFTP',
            'nombre_de_tentative'           => 'retryFTP',
            'retryftp'                      => 'retryFTP',
            'by_default__send'              => 'defaultftpdatasent',
            'by_default_send'               => 'defaultftpdatasent',
            'envoi_par_defaut'              => 'defaultftpdatasent',
            'defaultftpdatasent'            => 'defaultftpdatasent',
            'prefix_creation_folder'        => 'prefixFTPfolder',
            'prefix_de_creation_de_dossier' => 'prefixFTPfolder',
            'prefixFTPfolder'               => 'prefixFTPfolder',
        ];
    }

    private function getUserLastConnection(User $user)
    {
       return ($user->getLastConnection() != null) ? $user->getLastConnection()->format(DATE_ATOM): '';
    }
    /**
     * @param Request $request
     * @return UserHelper\Edit
     */
    private function getUserEditHelper(Request $request)
    {
        return new UserHelper\Edit($this->app, $request);
    }

    /**
     * @param Request $request
     * @return UserHelper\Manage
     */
    private function getUserManageHelper(Request $request)
    {
        return new UserHelper\Manage($this->app, $request);
    }

    /**
     * @return \ACL
     */
    private function getAclForConnectedUser()
    {
        return $this->getAclForUser($this->getAuthenticatedUser());

    }

    /**
     * @return ExporterInterface
     */
    private function getCsvExporter()
    {
        /** @var ExporterInterface $exporter */
        $exporter = $this->app['csv.exporter'];
        return $exporter;
    }

    /**
     * @param array $template
     * @return array
     */
    private function normalizeTemplateArray(array $template)
    {
        $templates = [];
        foreach ($template as $tmp) {
            if ('' === trim($tmp)) {
                continue;
            }

            $tmp = explode('_', $tmp);

            if (count($tmp) == 2) {
                $templates[$tmp[0]] = $tmp[1];
            }
        }
        return $templates;
    }

    /**
     * @param array $denials
     * @param array $templates
     * @return array
     */
    private function normalizeDenyArray(array $denials, array $templates)
    {
        $deny = [];
        foreach ($denials as $den) {
            $den = explode('_', $den);
            if (count($den) == 2 && !isset($templates[$den[0]])) {
                $deny[$den[0]][$den[1]] = $den[1];
            }
        }
        return $deny;
    }

    /**
     * @return RegistrationManipulator
     */
    private function getRegistrationManipulator()
    {
        return $this->app['manipulator.registration'];
    }

    /**
     * @param $filename
     * @param $contentType
     * @return Response
     */
    public function returnExampleFile($filename, $contentType)
    {
        $file = new \SplFileInfo($filename);

        if (!$file->isFile()) {
            $this->app->abort(400);
        }

        $response = new Response();
        $response->setStatusCode(200);
        $response->headers->set('Pragma', 'public');
        $response->headers->set('Content-Disposition', 'attachment; filename=' . $file->getFilename());
        $response->headers->set('Content-Length', $file->getSize());
        $response->headers->set('Content-Type', $contentType);
        $response->setContent(file_get_contents($file->getPathname()));

        return $response;
    }
}
