<?php

include_once(dirname(__FILE__).'/NewsPage.php');
include_once(dirname(__FILE__).'/NewsSource.php');
include_once(dirname(__FILE__).'/Import/Vismo.php');
include_once(dirname(__FILE__).'/Import/ZdechovNET.php');

function CategoryItemCompare($Item1, $Item2)
{
  if ($Item1['Index'] == $Item2['Index']) return 0;
  return $Item1['Index'] > $Item2['Index'] ? -1 : 1;
}

class ModuleNews extends Module
{
  public int $NewsCountPerCategory = 3;
  public string $UploadedFilesFolder = 'files/news/';
  public array $NewsSetting;

  function __construct(System $System)
  {
    parent::__construct($System);
    $this->Name = 'News';
    $this->Version = '1.0';
    $this->Creator = 'Chronos';
    $this->License = 'GNU/GPLv3';
    $this->Description = 'News and news groups management';
    $this->Dependencies = array(ModuleUser::GetName(), ModuleLog::GetName(), ModuleFile::GetName());
    $this->Models = array(NewsCategory::GetClassName(), News::GetClassName());
  }

  function DoStart(): void
  {
    $this->System->RegisterPage(['aktuality'], 'PageNews');
    $this->System->RegisterPage(['aktuality', 'subscription'], 'PageNewsSubscription');
    $this->System->RegisterPage(['aktuality', 'rss'], 'PageNewsRss');
    $this->System->RegisterPage(['aktuality', 'aktualizace'], 'PageNewsUpdate');
    Core::Cast($this->System)->FormManager->RegisterClass('News', array(
      'Title' => 'Aktualita',
      'Table' => 'News',
      'DefaultSortColumn' => 'Date',
      'DefaultSortOrder' => 1,
      'Items' => array(
        'Category' => array('Type' => 'TNewsCategory', 'Caption' => 'Kategorie', 'Default' => 0),
        'Title' => array('Type' => 'String', 'Caption' => 'Nadpis', 'Default' => ''),
        'Content' => array('Type' => 'Text', 'Caption' => 'Obsah', 'Default' => ''),
        'Date' => array('Type' => 'Date', 'Caption' => 'Datum', 'Default' => ''),
        'Author' => array('Type' => 'String', 'Caption' => 'Autor', 'Default' => ''),
        'Enclosure' => array('Type' => 'String', 'Caption' => 'Přílohy', 'Default' => ''),
        'User' => array('Type' => 'TUser', 'Caption' => 'Uživatel', 'Default' => ''),
        'IP' => array('Type' => 'IPv4Address', 'Caption' => 'IP adresa', 'Default' => '', 'ReadOnly' => true),
        'Link' => array('Type' => 'Hyperlink', 'Caption' => 'Odkaz', 'Default' => ''),
      ),
    ));
    Core::Cast($this->System)->FormManager->RegisterClass('NewsCategory', array(
      'Title' => 'Kategorie aktualit',
      'Table' => 'NewsCategory',
      'Items' => array(
        'Caption' => array('Type' => 'String', 'Caption' => 'Titulek', 'Default' => ''),
        'RSS' => array('Type' => 'Hyperlink', 'Caption' => 'Zdroj RSS', 'Default' => ''),
        'Permission' => array('Type' => 'Boolean', 'Caption' => 'Veřejné upravitelné', 'Default' => ''),
        'Sequence' => array('Type' => 'Integer', 'Caption' => 'Pořadí', 'Default' => ''),
        'Group' => array('Type' => 'Integer', 'Caption' => 'Skupina', 'Default' => ''),
        'News' => array('Type' => 'TNewsList', 'Caption' => 'Aktuality', 'Default' => ''),
      ),
    ));
    Core::Cast($this->System)->FormManager->RegisterFormType('TNewsCategory', array(
      'Type' => 'Reference',
      'Table' => 'NewsCategory',
      'Id' => 'Id',
      'Name' => 'Caption',
      'Filter' => '1',
    ));
    Core::Cast($this->System)->FormManager->RegisterFormType('TNewsList', array(
      'Type' => 'ManyToOne',
      'Table' => 'News',
      'Id' => 'Id',
      'Ref' => 'Category',
      'Filter' => '1',
    ));

    if ($this->System->ModuleManager->ModulePresent('Search'))
    {
      ModuleSearch::Cast($this->System->GetModule('Search'))->RegisterSearch('Novinky', 'News', array('Title', 'Content'));
    }
  }

  function GetIntranetCondition(): string
  {
    if (IsInternetAddr()) return ' AND (`Intranet`=0)';
      else return '';
  }

  function ShowNews(string $Category, int $ItemCount, int $DaysAgo): string
  {
    $ItemCount = abs($ItemCount);
    $DaysAgo = abs($DaysAgo);
    $DbResult = $this->Database->select('NewsCategory', '*', 'Id='.$Category);
    $Row = $DbResult->fetch_array();
    $Output = '<div class="NewsPanel"><div class="Title">'.$Row['Caption'];
    $Output .= '<div class="Action"><a href="aktuality/?category='.$Category.'">Zobrazit</a>';
    if (ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('News', 'Insert', 'Group', $Category))
      $Output .= ' <a href="aktuality/?action=add&amp;category='.$Category.'">Přidat</a>';
    $Output .= '</div></div><div class="Content">';
    $DbResult = $this->Database->query('SELECT `News`.*, `User`.`Name` FROM `News` LEFT JOIN `User` ON `User`.`Id`=`News`.`User`'.
      ' WHERE (`News`.`Category`='.$Category.') AND (DATE_SUB(NOW(), INTERVAL '.$DaysAgo.' DAY) < `News`.`Date`)'.$this->GetIntranetCondition().
      ' ORDER BY `News`.`Date` DESC LIMIT 0,'.$ItemCount);

    $Index = 0;
    $FontSize = 12;
    if ($DbResult->num_rows > 0)
    {
      $Output .= '<table class="NewsTable">';
      while ($Row = $DbResult->fetch_array())
      {
        if ($Row['Name'] == '') $Author = $Row['Author'];
          else $Author = $Row['Name'];
        $Output .= '<tr><td onclick="window.location=\'aktuality/?action=view&amp;id='.$Row['Id'].
          '\'" onmouseover="zobraz('."'new".$Category.$Index."'".')" style="cursor: pointer; margin: 0px;">'.
          '<table class="NewsItemFrame"><tr><td style="font-size: '.$FontSize.'pt"><strong>'.$Row['Title'].'</strong></td>'.
          '<td align="right" style="font-size: '.$FontSize.'pt">'.$Author.' ('.HumanDate($Row['Date']).')</td></tr></table>';
        $Output .= '<div id="new'.$Category.$Index.'" class="NewsTableItem">'.$this->ModifyContent($Row['Content']);
        if ($Row['Link'] != '') $Output .= '<br/><a href="'.$Row['Link'].'">Odkaz</a>';

        if ($Row['Enclosure'] != '')
        {
          $Output .= '<br />Přílohy: ';
          $Enclosures = explode(';', $Row['Enclosure']);
          foreach ($Enclosures as $Enclosure)
          {
            if (file_exists($this->UploadedFilesFolder.$Enclosure))
              $Output .= ' <a href="'.$this->UploadedFilesFolder.$Enclosure.'">'.$Enclosure.'</a>';
          }
        }
        $Output .= '</div></td></tr>';
        $Index = $Index + 1;
        $FontSize = $FontSize - 1;
      }
      $Output .= '</table>';
    }
    $Output .= '</div></div>';
    return $Output;
  }

  function LoadSettingsFromCookies(): void
  {
    // Initialize default news setting
    $this->NewsSetting = array();
    $I = 1;
    $DbResult = $this->Database->select('NewsCategory', '*', '1 ORDER BY Sequence');
    while ($NewsCategory = $DbResult->fetch_array())
    {
      $this->NewsSetting[] = array('CategoryId' => $NewsCategory['Id'], 'Index' => $I, 'Enabled' => 1,
        'ItemCount' => Core::Cast($this->System)->Config['Web']['News']['Count'], 'DaysAgo' => 
        Core::Cast($this->System)->Config['Web']['News']['DaysAgo'], 'Group' => $NewsCategory['Group']);
      $I++;
    }
    // Merge defaults with user setting
    if (array_key_exists('NewsSetting', $_COOKIE))
    {
      $NewsSettingCookie = unserialize($_COOKIE['NewsSetting']);
      foreach ($this->NewsSetting as $Index => $this->NewsSetting)
      {
        if (array_key_exists($Index, $NewsSettingCookie))
          $this->NewsSetting[$Index] = array_merge($this->NewsSetting, $NewsSettingCookie[$Index]);
      }
    }
  }

  function Show(): string
  {
    $Output = '';
    
    $this->LoadSettingsFromCookies();

    if (array_key_exists('Action', $_GET))
    {
      // Show news customize menu
      if ($_GET['Action'] == 'CustomizeNews')
      {
        $Output .= $this->ShowCustomizeMenu();
      }
    }

    $Output .= '<div onmouseout="skryj(predchozi)">';

    $ColumnCount = 2;
    $Output .= '<table style="width: 100%"><tr>';
    for ($Column = 1; $Column <= $ColumnCount; $Column++)
    {
      $Output .= '<td style="vertical-align: top; width: '.round(100 / $ColumnCount).'%;">';
      foreach ($this->NewsSetting as $SettingItem)
        if (($SettingItem['Enabled'] == 1) and ($SettingItem['Group'] == $Column))
          $Output .= $this->ShowNews($SettingItem['CategoryId'], $SettingItem['ItemCount'], $SettingItem['DaysAgo']);
      $Output .= '</td>';
    }
    $Output .= '</tr></table>';

    $Output .= '<a href="aktuality/subscription"><img class="RSSIcon" src="images/rss20.png" alt="Aktuality přes RSS" /></a>  <a href="aktuality/subscription">Automatické sledování novinek</a>';
    $Output .= '</div>';
    return $Output;
  }

  function ShowCustomizeMenu(): string
  {
    $Output = '<form action="?Action=CustomizeNewsSave" method="post">';
    $Output .= '<table width="100%" cellspacing="0" border="1"><tr><td><table cellspacing="0" width="100%">';
    $Output .= '<tr><th>Kategorie</th><th>Pozice</th><th>Zobrazit</th><th>Max. počet</th><th>Posledních dnů</th><th>Sloupec</th></tr>';
    $I = 0;
    foreach ($this->NewsSetting as $SettingItem)
    {
      $DbResult = $this->Database->select('NewsCategory', '*', 'Id='.$SettingItem['CategoryId']);
      $NewsCategory = $DbResult->fetch_array();
      $Output .= '<tr><td>'.$NewsCategory['Caption'].'</td><td align="center"><input type="text" size="2" name="NewsCategoryIndex'.$I.'" value="'.$SettingItem['Index'].'" /></td><td align="center"><input type="checkbox" name="NewsCategoryEnabled'.$I.'"';
      if ($SettingItem['Enabled'] == 1) $Output .= ' checked="checked"';
      $Output .= ' /></td>'.
      '<td align="center"><input type="text" size="2" name="NewsCategoryCount'.$I.'" value="'.$SettingItem['ItemCount'].'" />'.
      '<input type="hidden" name="NewsCategoryId'.$I.'" value="'.$SettingItem['CategoryId'].'" /></td>'.
      '<td align="center"><input type="text" size="3" name="NewsCategoryDaysAgo'.$I.'" value="'.$SettingItem['DaysAgo'].'" /></td>'.
      '<td><input type="text" size="3" name="NewsColumn'.$I.'" value="'.$SettingItem['Group'].'"/></td></tr>';
      $I++;
    }
    $Output .= '</table><input type="hidden" name="NewsCategoryCount" value="'.count($this->NewsSetting).'" /><input type="submit" value="Uložit" /></form></td></tr></table><br>';
    return $Output;
  }

  function CustomizeSave(): void
  {
    $Checkbox = array('' => 0, 'on' => 1);
    $Setting = array();
    for ($I = 0; $I < $_POST['NewsCategoryCount']; $I++)
    {
      if (($_POST['NewsCategoryDaysAgo'.$I] * 1) < 0) $_POST['NewsCategoryIndex'.$I] = 0;
      if (($_POST['NewsCategoryCount'.$I] * 1) < 0) $_POST['NewsCategoryCount'.$I] = 0;
      if (($_POST['NewsColumn'.$I] * 1) < 1) $_POST['NewsColumn'.$I] = 1;
      if (!array_key_exists('NewsCategoryEnabled'.$I, $_POST)) $_POST['NewsCategoryEnabled'.$I] = '';
      $Setting[] = array('CategoryId' => $_POST['NewsCategoryId'.$I], 'Enabled' => $Checkbox[$_POST['NewsCategoryEnabled'.$I]], 'ItemCount' => ($_POST['NewsCategoryCount'.$I]*1), 'DaysAgo' => ($_POST['NewsCategoryDaysAgo'.$I]*1), 'Index' => ($_POST['NewsCategoryIndex'.$I]*1),
      'Group' => $_POST['NewsColumn'.$I]);
    }
    // Sort indexes
    usort($Setting, 'CategoryItemCompare');
    $Setting = array_reverse($Setting);
    // Normalize indexes
    foreach ($Setting as $Index => $Item)
      $Setting[$Index]['Index'] = $Index + 1;

    // Store new cookie value
    $_COOKIE['NewsSetting'] = serialize($Setting);
    setcookie('NewsSetting', $_COOKIE['NewsSetting'], time() + 60 * 60 * 24 * 365);
  }

  function ModifyContentPrefix(string $Content, string $Prefix): string
  {
    $Result = '';

    // Make HTML link from URL
    $I = 0;
    while (strpos($Content, $Prefix) !== false)
    {
      $I = strpos($Content, $Prefix);
      if (($I > 0) and ($Content[$I - 1] != '"'))
      {
        $Result .= substr($Content, 0, $I);
        $Content = substr($Content, $I);
        if (strpos($Content, ' ') !== false)
          $URL = substr($Content, 0, strpos($Content, ' '));
        else $URL = substr($Content, 0);
        $Result .= '<a href="'.$URL.'">'.$URL.'</a>';
        $Content = substr($Content, strlen($URL));
      } else
      {
        $Result .= substr($Content, 0, $I + 1);
        $Content = substr($Content, $I + 1);
      }
    }
    $Result .= $Content;
    return $Result;
  }

  function ModifyContent(string $Content): string
  {
    return $this->ModifyContentPrefix($this->ModifyContentPrefix($Content, 'http://'), 'https://');
  }

  static function Cast(Module $Module): ModuleNews
  {
    if ($Module instanceof ModuleNews)
    {
      return $Module;
    }
    throw new Exception('Expected ModuleNews type but got '.gettype($Module));
  }
}

class News extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddReference('Category', NewsCategory::GetClassName(), true);
    $Desc->AddString('Title');
    $Desc->AddText('Content');
    $Desc->AddDate('Date');
    $Desc->AddString('Author');
    $Desc->AddString('Enclosure');
    $Desc->AddReference('User', User::GetClassName());
    $Desc->AddString('IP');
    $Desc->AddString('Link');
    return $Desc;
  }
}

class NewsCategory extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddString('Caption');
    $Desc->AddString('RSS');
    $Desc->AddBoolean('Permission');
    $Desc->AddInteger('Sequence');
    $Desc->AddInteger('Group');
    return $Desc;
  }
}
