<?php

include_once(dirname(__FILE__).'/Import/Seznamka.php');
include_once(dirname(__FILE__).'/Import/TanecniSkola.php');
include_once(dirname(__FILE__).'/Import/AstraPraha.php');
include_once(dirname(__FILE__).'/Import/Vavruska.php');
include_once(dirname(__FILE__).'/Import/SalsaDance.php');
include_once(dirname(__FILE__).'/Import/Amblar.php');
include_once(dirname(__FILE__).'/Import/MajkluvSvet.php');
include_once(dirname(__FILE__).'/Import/Csts.php');
include_once(dirname(__FILE__).'/Import/Facebook.php');
include_once(dirname(__FILE__).'/Import/Eso.php');
include_once(dirname(__FILE__).'/Import/Ella.php');
include_once(dirname(__FILE__).'/Import/MgDance.php');
include_once(dirname(__FILE__).'/Import/LaTropical.php');

abstract class Gender
{
  const Undefined = 0;
  const Male = 1;
  const Female = 2;
}

function GetTextBetween(string &$Text, string $Start, string $End): string
{
  $Result = '';
  if ((strpos($Text, $Start) !== false) and (strpos($Text, $End) !== false))
  {
    $Text = substr($Text, strpos($Text, $Start) + strlen($Start));
    $Result = substr($Text, 0, strpos($Text, $End));
    $Text = substr($Text, strpos($Text, $End) + strlen($End));
  }
  return $Result;
}

function HumanDateTimeToTime(string $DateTime): ?int
{
  if ($DateTime == '') return NULL;
  $DateTime = str_replace('. ', '.', $DateTime);
  $Parts = explode(' ', $DateTime);
  if (count($Parts) > 0)
  {
    $DateParts = explode('.', $Parts[0]);
    if (count($DateParts) == 1) $DateParts[1] = '0';
    if (count($DateParts) == 2) $DateParts[2] = '0';
  } else return NULL;
  if (count($Parts) > 1)
  {
    $TimeParts = explode(':', $Parts[1]);
    if (count($TimeParts) == 1) $TimeParts[1] = '0';
    if (count($TimeParts) == 2) $TimeParts[2] = '0';
  } else $TimeParts = array(0, 0, 0);
  $Result = mktime($TimeParts[0], $TimeParts[1], $TimeParts[2], $DateParts[1], $DateParts[0], $DateParts[2]);
  return $Result;
}

function HumanDateToTime(string $Date): ?int
{
  if ($Date == '') return NULL;
  return HumanDateTimeToTime($Date.' 0:0:0');
}

function DecodeHtmlEnt(string $str): string
{
  $prefix = '&#';
  $suffix = ';';
  $hexchar = 'x';
  $ret = html_entity_decode($str, ENT_COMPAT, 'UTF-8');
  $p2 = 0;
  for (;;)
  {
    $p = strpos($ret, $prefix, $p2);
    if ($p === FALSE)
      break;
    $p2 = strpos($ret, $suffix, $p);
    if ($p2 === FALSE)
    {
      $p2 = $p + strlen($prefix);
      while (($p2 < strlen($ret)) and is_numeric($ret[$p2]))
        $p2++;
      if ($p2 <= ($p + strlen($prefix))) break;
      $add = 0;
    } else $add = 1;

    if (substr($ret, $p + strlen($prefix), strlen($hexchar)) == $hexchar)
      $char = hexdec(substr($ret, $p + strlen($prefix) + strlen($hexchar), $p2 - $p - strlen($prefix) - strlen($hexchar)));
    else
      $char = intval(substr($ret, $p + strlen($prefix), $p2 - $p - strlen($prefix)));

    $newchar = iconv(
      'UCS-4', 'UTF-8',
      chr(($char >> 24) & 0xFF).chr(($char >> 16) & 0xFF).chr(($char >> 8) & 0xFF).chr($char & 0xFF)
    );
    $ret = substr_replace($ret, $newchar, $p, $add + $p2 - $p);
    $p2 = $p + strlen($newchar) + $add;
  }
  return $ret;
}

function RemoveHtmlComments(string $Content): string
{
  $Result = '';
  while (strpos($Content, '<!--') !== false)
  {
    $Result .= substr($Content, 0, strpos($Content, '<!--'));
    $Content = substr($Content, strpos($Content, '<!--') + 4);
    $Content = substr($Content, strpos($Content, '-->') + 3);
  }
  return $Result;
  //return preg_replace('/<!--(.|\s)*?-->/', '', $Content);
}

function is_alpha(string $Char): bool
{
  return (($Char >= 'a') and ($Char <= 'z')) or (($Char >= 'A') and ($Char <= 'Z'));
}

function is_white_space(string $Char): bool
{
  return ($Char == ' ') or ($Char == "\t");
}

function GetDefaultMeetFilter(string $Table = ''): string
{
  global $Config;

  if ($Table != '') $Table = $Table.'.';

  return '('.$Table.'Hidden=0) AND ('.$Table.'Time > "'.TimeToMysqlDateTime(time() - (int)$Config['MeetInterval']).'")';
}

function GetNumberBeforeText(string $Text, string $Needle): string
{
  $Result = '';
  for (;;)
  {
    $Pos = strpos($Text, $Needle);
    if ($Pos !== false)
    {
      if ((($Pos + strlen($Needle)) < strlen($Text)) and (is_alpha($Text[$Pos + strlen($Needle)])))
      {
        $Text = substr($Text, $Pos + 1);
        continue;
      }
      $Result = substr($Text, 0, $Pos);
      $Text = substr($Text, $Pos + 1);
      $Start = $Pos - 1;
      while (($Start >= 0) and (is_numeric($Result[$Start]) or is_white_space($Result[$Start])))
        $Start--;
      $Start++;
      $Result = trim(substr($Result, $Start, $Pos - $Start));
      if (is_numeric($Result)) break;
    } else break;
  }
  return $Result;
}

function GetNumberAfterText(string $Text, string $Needle): string
{
  $Result = '';
  for (;;)
  {
    $Pos = strpos($Text, $Needle);
    if ($Pos !== false)
    {
      if ((($Pos - 1) >= 0) and (is_alpha($Text[$Pos - 1])))
      {
        $Text = substr($Text, $Pos + 1);
        continue;
      }
      $Result = substr($Text, $Pos + strlen($Needle));
      $Text = substr($Text, $Pos + 1);
      $End = 0;
      while (($End < strlen($Result)) and (is_numeric($Result[$End]) or is_white_space($Result[$End])))
        $End++;
      $End--;

      $Result = trim(substr($Result, 0, $End + 1));
      if (is_numeric($Result)) break;
    } else break;
  }
  return $Result;
}

function GetAgeFromText(string $Text): string
{
  $Text = strtolower($Text);
  $Result = GetNumberAfterText($Text, 'je mi');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'je mi přes');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'let');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'rokov');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'roků');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'letou');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'čerstvých');
  if ($Result == '') {
    $Result = GetNumberAfterText($Text, 'jsem');
    if ($Result > 100) $Result = ''; // Age over 100 is probably not age but height
  }
  if ($Result == '') $Result = GetAgeHeightWeightFromText($Text)[0];
  if ($Result == '') {
    $Year = GetNumberAfterText($Text, 'ročník');
    if ($Year != '') $Result = date('Y', time()) - $Year;
  }
  if ($Result == '') {
    $Year = GetNumberAfterText($Text, 'ročník:');
    if ($Year != '') $Result = date('Y', time()) - $Year;
  }
  if ($Result == '') {
    $Year = GetNumberAfterText($Text, 'narozen roku');
    if ($Year != '') $Result = date('Y', time()) - $Year;
  }
  if ($Result == '') {
    $Year = GetNumberAfterText($Text, 'narozena roku');
    if ($Year != '') $Result = date('Y', time()) - $Year;
  }
  if ($Result == '') {
    $Result = GetNumberAfterText($Text, 'věk');
  }
  return $Result;
}

function GetHeightFromText(string $Text): string
{
  $Text = strtolower($Text);
  $Result = GetNumberAfterText($Text, 'měřím');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'merim');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'výška');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'cm');
  if ($Result == '') $Result = GetNumberBeforeText($Text, 'bez podpatků');
  if ($Result == '') {
    $Result = GetNumberAfterText($Text, 'jsem');
    if ($Result < 150) $Result = ''; // Height below 150 is probably not height but age
  }
  if ($Result == '') $Result = GetAgeHeightWeightFromText($Text)[1];
  return $Result;
}

function GetWeightFromText(string $Text): string
{
  $Text = strtolower($Text);
  $Result = GetNumberBeforeText($Text, 'kg');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'vážím');
  if ($Result == '') $Result = GetNumberAfterText($Text, 'váha');
  if ($Result == '') $Result = GetAgeHeightWeightFromText($Text)[2];
  return $Result;
}

function GetAgeHeightWeightFromText(string $Text): array
{
  $Result = array('', '', '');
  $Pattern = '/[0-9]+\/[0-9]+\/[0-9]+/i';
  if (preg_match_all($Pattern, $Text, $Matches))
  {
    $Result = explode('/', $Matches[0][0]);
    // Avoid dates in a form day/month/year
    if ($Result[2] > 150) $Result = array('', '', '');
  } else
  {
    $Pattern = '/[0-9]+\/[0-9]+/i';
    if (preg_match_all($Pattern, $Text, $Matches))
    {
      $Result = explode('/', $Matches[0][0]);
      // If first number is over 100 then its probably height/weight
      if ($Result[0] > 100) $Result = array('', $Result[0], $Result[1]);
      $Result[] = '';
    }
  }
  return $Result;
}

function GetNameFromText(string $Text): string
{
  return '';
}

function GetEmailFromText(string $Text): string
{
  $Result = '';
  if (strpos($Text, '@') !== false)
  {
    $Pattern = '/[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.([a-z]{2,4})(?:\.[a-z]{2})?/i';
    preg_match_all($Pattern, $Text, $Matches);
    if ((count($Matches) > 0) and (count($Matches[0]) > 0) and ($Matches[0][0] != ''))
    {
      $Result = $Matches[0][0];
    }
  }
  return $Result;
}

$Locations = array(
  'praha' => 'Praha',
  'prahy' => 'Praha',
  'praze' => 'Praha',
  'brno' => 'Brno',
  'brně' => 'Brno',
  'ostrava' => 'Ostrava',
  'ostravě' => 'Ostrava',
  'ostravy' => 'Ostrava',
  'olomouc' => 'Olomouc',
  'liberec' => 'Liberec',
  'opava' => 'Opava',
  'opave' => 'Opava',
  'plzeň' => 'Plzeň',
  'plzni' => 'Plzeň',
  'vyškov' => 'Vyškov',
  'mladá boleslav' => 'Mladá Boleslav',
  'mladé boleslavi' => 'Mladá Boleslav',
  'litoměřice' => 'Litoměřice',
  'sokolov' => 'Sokolov',
  'mikulov' => 'Mikulov',
  'havířov' => 'Havířov',
  'kolín' => 'Kolín',
  'kroměříž' => 'Kroměříž',
  'hradec králové' => 'Hradec Králové',
);

function GetLocationFromText(string $Text): string
{
  global $Locations;

  $Text = strtolower($Text);

  foreach ($Locations as $Index => $Location)
  {
    if (strpos($Text, $Index) !== false) return $Location;
  }
  return '';
}

function GetGenderFromName(string $Text): string
{
  $Gender = Gender::Male;
  $Ending = substr($Text, -2);
  if (($Ending == 'na') or ($Ending == 'ta') or ($Ending == 'va') or
    ($Ending == 'ka') or ($Ending == 'ga') or ($Ending == 'ie') or
    ($Ending == 'la') or ($Ending == 'za') or ($Ending == 'še') or
    ($Ending == 'ra') or ($Ending == 'da') or ($Ending == 'sa') or
    ($Ending == 'ce') or ($Ending == 'id') or ($Ending == 'ša') or
    ($Ending == 'ma') or ($Ending == 'ja') or ($Ending == 'ia') or
    ($Ending == 'ha') or ($Ending == 'is'))
    return $Gender = Gender::Female;
  return $Gender;
}

class MeetSources
{
  public Database $Database;

  function Parse(?int $Id = null): string
  {
    $Output = '';
    $Where = '1';
    if (($Id != null) and is_numeric($Id)) $Where .= ' AND (Id='.$Id.')';
    $DbResult = $this->Database->select('MeetSource', '*', $Where);
    while ($DbRow = $DbResult->fetch_assoc())
    {
      if ($DbRow['Enabled'] == 1)
      {
        $Method = $DbRow['Method'];
        if ($Method == 'hes') $Source = new MeetSourceTanecniSkola();
        else if ($Method == 'vavruska') $Source = new MeetSourceVavruska();
        else if ($Method == 'salsadance') $Source = new MeetSourceSalsaDance();
        else if ($Method == 'astra') $Source = new MeetSourceAstraPraha();
        else if ($Method == 'seznamka') $Source = new MeetSourceSeznamka();
        else if ($Method == 'amblar') $Source = new MeetSourceAmblar();
        else if ($Method == 'majkluvsvet') $Source = new MeetSourceMajkluvSvet();
        else if ($Method == 'csts') $Source = new MeetSourceCsts();
        else if ($Method == 'facebook') $Source = new MeetSourceFacebook();
        else if ($Method == 'eso') $Source = new MeetSourceEso();
        else if ($Method == 'ella') $Source = new MeetSourceElla();
        else if ($Method == 'mgdance') $Source = new MeetSourceMgDance();
        else if ($Method == 'latropical') $Source = new MeetSourceLaTropical();
        else {
          $Output .= 'Unsupported parse method: '.$Method.'<br/>';
          continue;
        }
        $Source->Database = $this->Database;
        $Source->Id = $DbRow['Id'];
        $Source->URL = $DbRow['URL'];
        $Source->Method = $Method;
        $Source->Name = $DbRow['Name'];
        $Output .= $Source->DoImport();
      } else $Output .= 'Parser '.$DbRow['Name'].' (#'.$DbRow['Id'].') disabled.<br/>'."\n";
    }
    return $Output;
  }
}

class MeetSource
{
  public string $Name;
  public string $URL;
  public string $Method;
  public string $Id;
  public Database $Database;
  public array $MeetItems;
  public bool $AddCompareTime;
  public bool $AddCompareRemoteId;
  public int $AddTimeInterval;
  public int $AddedCount;

  function __construct()
  {
    $this->MeetItems = array();
    $this->AddedCount = 0;
    $this->AddCompareTime = true;
    $this->AddCompareRemoteId = false;
    $this->AddTimeInterval = 0;
  }

  function Import(): string
  {
    return '';
  }

  function DoImport(): string
  {
    $this->MeetItems = array();
    $this->AddedCount = 0;
    $Output = 'Parsing '.$this->Name.' (#'.$this->Id.')...';
    $Output .= $this->Import();
    $Output .= ' parsed: '.count($this->MeetItems);
    foreach ($this->MeetItems as $MeetItem)
    {
      if ($MeetItem->IsSpam()) continue;
      $this->AddedCount += $MeetItem->AddIfNotExist($this->AddTimeInterval, $this->AddCompareTime, $this->AddCompareRemoteId);
    }
    $Output .= ', new added: '.$this->AddedCount;
    $Output .= '</br>'."\n";
    return $Output;
  }
}

class MeetItem
{
  public Database $Database;
  public string $Name = '';
  public string $Message = '';
  public ?int $Time = 0;
  public int $Gender = Gender::Undefined;
  public string $Phone = '';
  public string $Email = '';
  public string $Age = '';
  public string $Height = '';
  public int $Source = 0;
  public string $Weight = '';
  public string $Location = '';
  public string $Image = '';
  public string $Link = '';
  public string $Title = '';
  public string $Level = '';
  public string $RemoteId = '';

  function AddIfNotExist(int $TimeInterval = 0, bool $CompareTime = true, bool $CompareRemoteId = false): int
  {
    $Where = '(`Message` = "'.$this->Database->real_escape_string($this->Message).'") AND '.
      '(`Email` = "'.$this->Database->real_escape_string($this->Email).'") AND '.
      '(`Source` = '.$this->Source.')';
    if ($CompareTime)
      $Where .= ' AND (`Time` >= "'.$this->Database->real_escape_string(TimeToMysqlDateTime($this->Time - $TimeInterval)).'") AND '.
      '(`Time` <= "'.$this->Database->real_escape_string(TimeToMysqlDateTime($this->Time + $TimeInterval)).'")';
    if ($CompareRemoteId)
      $Where .= ' AND (`RemoteId` = "'.$this->Database->real_escape_string($this->RemoteId).'")';
    $DbResult = $this->Database->select('MeetItem', '*', $Where);
    if ($DbResult->num_rows == 0)
    {
      if ($this->Age == '') $Age = null;
        else $Age = $this->Age;
      if ($this->Height == '') $Height = null;
        else $Height = $this->Height;
      if ($this->Weight == '') $Weight = null;
        else $Weight = $this->Weight;
      $this->Database->insert('MeetItem', array(
        'Source' => $this->Source,
        'Link' => $this->Link,
        'Email' => $this->Email,
        'Message' => $this->Message,
        'Time' => TimeToMysqlDateTime($this->Time),
        'Gender' => $this->Gender,
        'Age' => $Age,
        'Phone' => $this->Phone,
        'Name' => $this->Name,
        'Height' => $Height,
        'Weight' => $Weight,
        'Location' => $this->Location,
        'RemoteId' => $this->RemoteId,
        'TimeImport' => 'NOW()',
      ));
      $Result = 1;
    } else $Result = 0;
    return $Result;
  }

  function IsSpam(): bool
  {
    $Keywords = array('půjčk', 'úvěr');
    foreach ($Keywords as $Keyword)
    {
      if (strpos($this->Message, $Keyword) !== false)
      {
        return true;
      }
    }
    return false;
  }
}
