<?php
/**
 * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
 *
 * BOKEH is free software; you can redistribute it and/or modify
 * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
 * the Free Software Foundation.
 *
 * There are special exceptions to the terms and conditions of the AGPL as it
 * is applied to this software (see README file).
 *
 * BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
 * along with BOKEH; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 */


class Cosmo_DeleteItemsControllerIndexActionTest extends CosmoControllerTestCase {

  public function setUp() {
    parent::setUp();

    $this->fixture(Class_IntBib::class,
                   ['id' => 0,
                    'nom_court' => 'Authume']);

    $this->fixture(Class_IntBib::class,
                   ['id' => 5,
                    'nom_court' => 'Foucherans']);

    $this->dispatch('/cosmo/delete-items/index');
  }


  /** @test */
  public function titleShouldBeSuppressionDeNoticeOuDExemplaires() {
    $this->assertXPathContentContains('//h1',
                                      'Suppression des notices ou des exemplaires');
  }


  /** @test */
  public function pageShouldContainsButtonSupprimerToutesLesNoticesDeLaBase() {
    $this->assertXPathContentContains('//button[@data-url="/cosmo/delete-items/all-dashboard"]', 'Supprimer toutes les notices de la base');
  }


  /** @test */
  public function pageShouldContainsDeletionNotice() {
    $this->assertXPathContentContains('//p[@class="notice"]', 'Les boutons suivants vous permettent de supprimer les exemplaires d\'une bibliothèque.');
  }


  /** @test */
  public function tableShouldContainsLibraryIdZero() {
    $this->assertXPath('//table/tbody/tr[1]/td[1][contains(text(),"0")]');
  }


  /** @test */
  public function tableShoudContainsLibraryAuthume() {
    $this->assertXPathContentContains('//table/tbody/tr[1]/td[2]', 'Authume');
  }


  /** @test */
  public function tableShouldContainsDeleteItemsLibraryIdZero() {
    $this->assertXPath('//table/tbody/tr[1]/td[3]/a[@href="/cosmo/delete-items/library-dashboard/id/0"]/img[@title="Supprimer les exemplaires"]');
  }


  /** @test */
  public function tableShouldContainsLibraryIdFive() {
    $this->assertXPathContentContains('//table/tbody/tr[2]/td[1]', '5');
  }


  /** @test */
  public function tableShouldContainsLibraryFocherans() {
    $this->assertXPathContentContains('//table/tbody/tr[2]/td[2]', 'Foucherans');
  }


  /** @test */
  public function tableShouldContainsDeleteItemsLibraryIdFive() {
    $this->assertXPath('//table/tbody/tr[2]/td[3]/a[@href="/cosmo/delete-items/library-dashboard/id/5"]/img[@title="Supprimer les exemplaires"]');
  }
}




abstract class Cosmo_DeleteItemsControllerAllTestCase extends CosmoControllerTestCase {

  public function setUp() {
    parent::setUp();

    $this->fixture(Class_Notice::class,
                   ['id' => 1]);
    $this->fixture(Class_Notice::class,
                   ['id' => 2]);
    $this->fixture(Class_Notice::class,
                   ['id' => 3]);
    $this->fixture(Class_Notice::class,
                   ['id' => 4]);

    $this->fixture(Class_Notice_SerialArticles::class,
                   ['id' => 1,
                    'clef_chapeau' => 'MY-KEY',
                    'clef_numero' => '001']);

    $this->fixture(Class_NoticeSuccincte::class,
                   ['id' => 1]);
    $this->fixture(Class_Exemplaire::class,
                   ['id' => 1]);
    $this->fixture(Class_StatsNotices::class,
                   ['id' => 1]);
    $this->fixture(Class_CodifTags::class,
                   ['id' => 1]);
    $this->fixture(Class_Cosmogramme_Integration::class,
                   ['id' => 1]);
    $this->fixture(Class_IntAnalyse::class,
                   ['id' => 1]);
    $this->fixture(Class_Pret::class,
                   ['id' => 1]);
    $this->fixture(Class_Reservation::class,
                   ['id' => 1]);

    Class_CosmoVar::setValueOf('cache_path', './cosmogramme/fichiers/my_cache');
    Class_CosmoVar::setValueOf('integration_path', './cosmogramme/fichiers/my_integration');
    Class_CosmoVar::setValueOf('log_path', './cosmogramme/fichiers/my_log');

    $disk = (new Storm_FileSystem_Volatile)
      ->mkdir('cosmogramme/fichiers/my_cache')
      ->mkdir('cosmogramme/fichiers/my_integration')
      ->mkdir('cosmogramme/fichiers/my_log')
      ->cd('cosmogramme/fichiers/my_cache')
      ->touch('8934789UI98E.cache')
      ->cd('../my_integration')
      ->touch('9456G6734YC.txt')
      ->cd('/');

    ZendAfi_View_Helper_Cosmo_DeleteItemsAllDashboard::setFileSystem($disk);

    $fs = $this->mock();
    $fs->whenCalled('opendir')
       ->answers('dir_pointer')

       ->whenCalled('readdir')
       ->willDo(function()
       {
         Class_Cosmogramme_Cleaner::getFileSystem()->whenCalled('readdir')
                                                   ->answers(false);
         return '8934789UI98E.cache';
       })

       ->whenCalled('is_dir')
       ->answers(false)

       ->whenCalled('unlink')
       ->answers(true)

       ->whenCalled('closedir')
       ->answers(true);

    Class_Cosmogramme_Cleaner::setFileSystem($fs);
  }


  public function tearDown() {
    ZendAfi_View_Helper_Cosmo_DeleteItemsAllDashboard::setFileSystem(null);
    Class_Cosmogramme_Cleaner::setFileSystem(null);
    return parent::tearDown();
  }
}




class Cosmo_DeleteItemsControllerAllRunDeleteArticleRecordsTest
  extends Cosmo_DeleteItemsControllerAllTestCase {

  public function stepClassMapping() {
    return [[0, Class_Notice::class],
            [1, Class_Notice_SerialArticles::class],
            [2, Class_NoticeSuccincte::class],
            [3, Class_Exemplaire::class],
            [4, Class_StatsNotices::class],
            [5, Class_CodifTags::class],
            [6, Class_Cosmogramme_Integration::class],
            [7, Class_IntAnalyse::class],
            [8, Class_Pret::class],
            [9, Class_Reservation::class]];
  }


  /**
   * @dataProvider stepClassMapping
   * @test
   */
  public function pageShouldContainsNextUrlWithNoticesSuccinctes(int $step, string $class) {
    $this->dispatch('/cosmo/delete-items/all/step/' . $step . '/counter/' . $step );
    $step++;
    $this->assertXPath('//div[@data-delete-url="/cosmo/delete-items/all/step/' . $step . '/counter/' . $step . '"]');
  }


  /**
   * @dataProvider stepClassMapping
   * @test
   */
  public function entitiesShouldBeDeleted(int $step, string $class) {
    $this->dispatch('/cosmo/delete-items/all/step/' . $step . '/counter/' . $step );
    $this->assertEmpty($class::findAll());
  }

  /**
   * @dataProvider stepClassMapping
   * @test
   */
  public function pageShouldContainsTitleSuppressionEnCours(int $step, string $class) {
    $this->dispatch('/cosmo/delete-items/all/step/' . $step . '/counter/' . $step );
    $this->assertXPathContentContains('//h3', 'Suppression en cours');
  }


  public function stepDirectoryMapping() {
    return [[10, 'cache_path'],
            [11, 'integration_path'],
            [12, 'log_path']
    ];
  }


  /**
   * @dataProvider stepDirectoryMapping
   * @test
   */
  public function directoryShouldBeEmpty(int $step, string $variable) {
    $path = Class_CosmoVar::getValueOf($variable);
    $this->dispatch('/cosmo/delete-items/all/step/' . $step . '/counter/' . $step );
    $this->assertFalse(Class_Cosmogramme_Cleaner::getFileSystem()->readdir($path));
  }
}




class Cosmo_DeleteItemsControllerAllDashboardTest
  extends Cosmo_DeleteItemsControllerAllTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/all-dashboard');
  }


  /** @test */
  public function pageTitleShouldBeDeleteAllRecordsAndItems() {
    $this->assertXPathContentContains('//h1', 'Supprimer toutes les notices et tous les exemplaires');
  }


  /** @test */
  public function pageShouldContainConfirmButtonLancerLaSuppression() {
    $this->assertXPathContentContains('//button[@id="run_delete"]', 'Lancer la suppression');
  }


  /** @test */
  public function pageShouldContainBackButton() {
    $this->assertXPathContentContains('//button[@class="back admin-button"]', 'Retour');
  }


  /** @test */
  public function pageShouldContainModelsWarning() {
    $this->assertXPathContentContains('//p[@class="notice"]', 'Êtes-vous sûr de vouloir supprimer les données suivantes');
  }


  /** @test */
  public function pageShouldContain4Notices() {
    $this->assertXPathContentContains('//li', '4 notices');
  }


  public function modelsToCount() : array {
    return
      [['notices'],
       ['notices d\'articles'],
       ['notices succinctes'],
       ['exemplaires'],
       ['statistiques des notices'],
       ['codifications de tags'],
       ['integrations'],
       ['analyses d\'intégrations'],
       ['prêts'],
       ['réservations']];
  }


  /**
   * @test
   * @dataProvider modelsToCount
   */
  public function pageShouldContainModelLabel($label) {
    $this->assertXPathContentContains('//ul/li', $label);
  }


  public function filesToCount() : array {
    return [['my_cache'],
            ['my_integration'],
            ['my_log']];
  }


  /**
   * @test
   * @dataProvider filesToCount
   */
  public function pageShouldContainFolderToDelete($dir_name) {
    $this->assertXPathContentContains('//ul/li', './cosmogramme/fichiers/' . $dir_name);
  }


  /** @test */
  public function pageShouldContainsFolderMyCacheWith1Files() {
    $this->assertXPathContentContains('//ul/li', './cosmogramme/fichiers/my_cache (1 fichiers)');
  }


  /** @test */
  public function pageShouldContainsFolderMyIntegrationWith1Files() {
    $this->assertXPathContentContains('//ul/li', './cosmogramme/fichiers/my_integration (1 fichiers)');
  }


  /** @test */
  public function pageShouldContainsFolderMyLogWith1Files() {
    $this->assertXPathContentContains('//ul/li', './cosmogramme/fichiers/my_log (0 fichiers)');
  }


  /** @test */
  public function pageShouldHaveScriptAjaxDelete() {
    $this->assertXPath('//script[contains(@src, "/public/admin/js/ajax-delete/ajax-delete.js")]');
  }


  /** @test */
  public function pageShouldHaveScriptModalLoading() {
    $this->assertXPath('//script[contains(@src, "/public/admin/js/modal-loading/modal-loading.js")]');
  }


  /** @test */
  public function pageShouldHaveCssModalLoading() {
    $this->assertXPath('//link[contains(@href, "/public/admin/js/modal-loading/modal-loading.css")]');
  }


  /** @test */
  public function pageShouldHaveScriptToInitAjaxDeleteOnDeleteAll() {
    $this->assertXPathContentContains('//script', '$(function(){$("#delete_all").ajax_delete();});');
  }


  /** @test */
  public function pageShouldHaveDivIdDeleteAllWithDataAfterDeleteUrlDashboard() {
    $this->assertXPath('//div[@id="delete_all"][@data-after-delete-url="/cosmo/delete-items/all-dashboard"]');
  }


  /** @test */
  public function pageShouldHaveDivIdDeleteAllWithDataDeleteUrlAll() {
    $this->assertXPath('//div[@id="delete_all"][@data-delete-url="/cosmo/delete-items/all/step/0/counter/0"]');
  }
}




abstract class Cosmo_DeleteItemsControllerLibraryTestCase extends CosmoControllerTestCase {

  public function setUp() {
    parent::setUp();

    $this->fixture(Class_IntBib::class,
                   ['id' => 1,
                    'id_bib' => 1,
                    'nom_court' => 'Champvans']);

    $this->fixture(Class_IntBib::class,
                   ['id' => 3,
                    'ib_bib' => 3,
                    'nom_court' => 'Authume']);

    $this->fixture(Class_Notice::class,
                   ['id' => 1,
                    'facettes' => 'HCCC001 B1 B3']);
    $this->fixture(Class_Notice::class,
                   ['id' => 2,
                    'facettes' => 'HCCC001 B1 B4 B33']);
    $this->fixture(Class_Notice::class,
                   ['id' => 3,
                    'facettes' => 'HCCC001 B1 B333 B5']);
    $this->fixture(Class_Notice::class,
                   ['id' => 4,
                    'facettes' => 'HCCC001 B3']);

    foreach (range(5, 104) as $id)
      $this->fixture(Class_Notice::class,
                     ['id' => $id,
                      'facettes' => 'HCCC001']);

    $this->fixture(Class_Exemplaire::class,
                   ['id' => 1,
                    'id_bib' => 1,
                    'id_notice' => 1]);

    $this->fixture(Class_Exemplaire::class,
                   ['id' => 2,
                    'id_bib' => 3,
                    'id_notice' => 1]);

    $this->fixture(Class_Exemplaire::class,
                   ['id' => 3,
                    'id_bib' => 3,
                    'id_notice' => 2]);

    $this->fixture(Class_Exemplaire::class,
                   ['id' => 4,
                    'id_bib' => 3,
                    'id_notice' => 3]);

    foreach (range(5, 104) as $item_id)
      $this->fixture(Class_Exemplaire::class,
                     ['id' => $item_id,
                      'id_bib' => 3]);

    $this->fixture(Class_NoticeSuccincte::class,
                   ['id' => 1,
                    'id_bib' => 1]);
    $this->fixture(Class_NoticeSuccincte::class,
                   ['id' => 2,
                    'id_bib' => 3]);

    foreach (range(3, 102) as $id)
      $this->fixture(Class_NoticeSuccincte::class,
                     ['id' => $id,
                      'id_bib' => 3]);

    $this->fixture(Class_Notice_SerialArticles::class,
                   ['id' => 1,
                    'clef_chapeau' => 'MY-KEY',
                    'clef_numero' => '001']);

    $this->fixture(Class_CodifTags::class,
                   ['id' => 1]);
  }
}




class Cosmo_DeleteItemsControllerLibraryDashboardTest
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/library-dashboard/id/1');
  }


  /** @test */
  public function pageTitleShouldBeDeleteItemsForChampvans() {
    $this->assertXPathContentContains('//h1', 'Supprimer tous les exemplaires de Champvans');
  }


  /** @test */
  public function pageShouldContainConfirmButtonLancerLaSuppression() {
    $this->assertXPathContentContains('//button[@id="run_delete"]', 'Lancer la suppression');
  }


  /** @test */
  public function pageShouldContainBackButton() {
    $this->assertXPathContentContains('//button[@class="back admin-button"]', 'Retour');
  }


  /** @test */
  public function pageShouldContainModelsWarning() {
    $this->assertXPathContentContains('//p[@class="notice"]', 'Êtes-vous sûr de vouloir supprimer les données suivantes');
  }
}




class Cosmo_DeleteItemsControllerLibraryActionFirstStepFirstRangeTest
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/2/step/0/counter/0/limit/100');
  }


  /** @test */
  public function pageShouldContainNextStepUrl() {
    $this->assertXPath('//div[@data-delete-url="/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/2/step/0/counter/100/limit/100"]');
  }


  /** @test */
  public function hundredItemsShouldHaveBeenDeletedForLibraryThree() {
    $this->assertEquals(3, count(Class_Exemplaire::findAllBy(['id_bib' => 3])));
  }
}




class Cosmo_DeleteItemsControllerLibraryActionFirstStepSecondRangeTest
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    Class_Exemplaire::deleteBy(['id <' => 100]);

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/2/step/0/counter/100');
  }


  /** @test */
  public function pageShouldContainNextStepUrl() {
    $this->assertXPath('//div[@data-delete-url="/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/2/step/1/counter/0"]');
  }


  /** @test */
  public function allItemsShouldHaveBeenDeletedForLibraryThree() {
    $this->assertCount(0, Class_Exemplaire::findAllBy(['id_bib' => 3]));
  }
}




class Cosmo_DeleteItemsControllerLibraryActionSecondStepFirstRangeTest
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/1/counter/0/limit/100');
  }


  /** @test */
  public function pageShouldContainNextStepUrl() {
    $this->assertXPath('//div[@data-delete-url="/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/1/counter/100/limit/100"]');
  }


  /** @test */
  public function hundredRecordsShouldHaveBeenDeletedForLibraryThree() {
    $this->assertCount(1, Class_NoticeSuccincte::findAllBy(['id_bib' => 3]));
  }
}




class Cosmo_DeleteItemsControllerLibraryActionSecondStepSecondRangeTest
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    Class_NoticeSuccincte::deleteBy(['id <' => 100]);

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/1/counter/100');
  }


  /** @test */
  public function pageShouldContainNextStepUrl() {
    $this->assertXPath('//div[@data-delete-url="/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/2/counter/0"]');
  }


  /** @test */
  public function allRecordsShouldHaveBeenDeletedForLibraryThree() {
    $this->assertCount(0, Class_NoticeSuccincte::findAllBy(['id_bib' => 3]));
  }
}




class Cosmo_DeleteItemsControllerLibraryActionDefaultLimitStep0Test
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/0/counter/0');
  }


  /** @test */
  public function allItemsFromBib_3_ShouldBeDeleted() {
    $this->assertEmpty(Class_Exemplaire::findAllBy(['id_bib' => 3]));
  }
}




class Cosmo_DeleteItemsControllerLibraryActionDefaultLimitStep2Test
  extends Cosmo_DeleteItemsControllerLibraryTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('/cosmo/delete-items/library/id/3/count_items/103/count_succinct_records/101/step/2/counter/0');
    Class_Notice::clearCache();
  }


  /** @test */
  public function firstNoticeShouldHaveLostFacetB3() {
    $this->assertEquals('HCCC001 B1', Class_Notice::find(1)->getFacettes());
  }


  /** @test */
  public function secondNoticeShouldHaveLostFacetB4AndB1() {
    $this->assertEquals('HCCC001 B1 B4 B33', Class_Notice::find(2)->getFacettes());
  }


  /** @test */
  public function thirdNoticeShouldHaveLostFacetB5() {
    $this->assertEquals('HCCC001 B1 B333 B5', Class_Notice::find(3)->getFacettes());
  }


  /** @test */
  public function fourthNoticeShouldHaveLostFacetB3() {
    $this->assertEquals('HCCC001', Class_Notice::find(4)->getFacettes());
  }
}