<?php
namespace Shared\Helpers;
class Helpers
{
  static function canAddRedirect( $from, $to, $lang_id = null )
  {
    global $mdb;

    if ( !$from or !$to or $from === $to )
      return false;

    $where = [];
    if ( null !== $lang_id )
      $where['lang_id'] = $lang_id;

    $redirects = $mdb -> select( 'pp_redirects', [ 'from', 'to' ], $where );

    $redirectMap = [];
    foreach ( $redirects as $redirect )
    {
      if ( !isset( $redirectMap[$redirect['from']] ) )
        $redirectMap[$redirect['from']] = [];

      if ( !in_array( $redirect['to'], $redirectMap[$redirect['from']], true ) )
        $redirectMap[$redirect['from']][] = $redirect['to'];
    }

    if ( !isset( $redirectMap[$from] ) )
      $redirectMap[$from] = [];

    if ( !in_array( $to, $redirectMap[$from], true ) )
      $redirectMap[$from][] = $to;

    $visited = [];
    $stack = [ $to ];
    while ( !empty( $stack ) )
    {
      $current = array_pop( $stack );

      if ( $current === $from )
        return false;

      if ( isset( $visited[$current] ) )
        continue;

      $visited[$current] = true;

      if ( isset( $redirectMap[$current] ) )
      {
        foreach ( $redirectMap[$current] as $next )
          if ( !isset( $visited[$next] ) )
            $stack[] = $next;
      }
    }

    return true;
  }

  static public function clear_product_cache( int $product_id )
  {
    if ( class_exists('Redis') )
    {
      try
      {
        $cacheHandler = new \Shared\Cache\CacheHandler();
        // Wyczyść cache produktu dla wszystkich języków i permutacji
        $cacheHandler -> deletePattern( "shop\\product:$product_id:*" );
        // Wyczyść cache związane z opcjami ilościowymi
        $cacheHandler -> deletePattern( "\\shop\\Product::get_product_permutation_quantity_options:$product_id:*" );
        // Wyczyść cache zestawów produktów
        $cacheHandler -> deletePattern( "\\shop\\Product::product_sets_when_add_to_basket:$product_id" );
      }
      catch (\Exception $e)
      {
        error_log("Błąd podczas czyszczenia cache produktu: " . $e->getMessage());
      }
    }
  }

  static public function remove_special_chars( $string ) {
    return str_ireplace( array( '\'', '"', ',' , ';', '<', '>' ), ' ', $string );
  }

  static public function removeDuplicates( $array, $param ) {
    $result = [];
    foreach ($array as $key => $subArray) {
      $idsSeen = [];
      foreach ($subArray as $subKey => $item) {
        if (!in_array($item[ $param ], $idsSeen)) {
          $idsSeen[] = $item[ $param ];
          $result[$key][] = $item;
        }
      }
    }
    return $result;
  }

  static public function generate_webp_image($file, $compression_quality = 85)
  {
    if ( strpos( $file, 'thumb/' ) !== false )
    {
      $file_tmp = explode( '/', $file );

      $width = $file_tmp[1];
      if ( empty( $width ) and $width !== '0' )
        $width = 500;

      $height = $file_tmp[2];
      if ( empty( $height ) and $height !== '0' )
        $height = 500;

      for ( $i = 0; $i <= 2; $i++ )
        unset( $file_tmp[$i] );

      $img_src = implode( '/', $file_tmp );

      $crop_w   = $_GET['c_w'];
      $crop_h   = $_GET['c_h'];

      $img_md5    = md5( $img_src . $height . $width . $crop_h . $crop_w );
      $file  = 'thumbs/' . $img_md5[0] . '/' . $img_md5[1] . '/' . $img_md5[2] . '/' . $img_md5;
    }

    if ( !file_exists( $file ) )
      return false;

    $output_file = 'cache/' . $file . '.webp';
    if ( file_exists( $output_file ) )
      return $output_file;

    $file_type = mime_content_type( $file );

    if ( function_exists( 'imagewebp' ) )
    {
      switch ( $file_type )
      {
        case 'image/jpeg':
          $image = imagecreatefromjpeg($file);
          break;

        case 'image/png':
          $image = imagecreatefrompng($file);
          imagepalettetotruecolor($image);
          imagealphablending($image, true);
          imagesavealpha($image, true);
          break;

        case 'image/gif':
          $image = imagecreatefromgif($file);
          break;

        default:
          return false;
      }

      $dir = dirname($output_file);
      if (!is_dir($dir))
        mkdir($dir, 0755, true);

      $result = imagewebp($image, $output_file, $compression_quality);
      if (false === $result)
        return false;

      imagedestroy($image);

      return $output_file;
    }
    elseif (class_exists('Imagick'))
    {
      $dir = dirname($output_file);
      if (!is_dir($dir))
        mkdir($dir, 0755, true);

      $image = new \Imagick();
      $image->readImage($file);

      if ($file_type === 'png')
      {
        $image->setImageFormat('webp');
        $image->setImageCompressionQuality($compression_quality);
        $image->setOption('webp:lossless', 'true');
      }

      $image->writeImage($output_file);
      return $output_file;
    }

    return false;
  }

  public static function is_array_fix( $value )
  {
    if ( is_array( $value ) and count( $value ) )
      return true;
    return false;
  }

  public static function delete_cache()
  {
    self::delete_dir( '../cache/' );
    self::delete_dir( '../temp/' );
    self::delete_dir( '../cron/temp/' );
    self::delete_dir( 'temp/' );
  }

  public static function pretty_date( $format, $timestamp = null )
  {
    $to_convert = array(
            'l' => array( 'dat' => 'N', 'str' => array( 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela' ) ),
            'F' => array( 'dat' => 'n', 'str' => array( 'styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec', 'lipiec', 'sierpień', 'wrzesień', 'październik', 'listopad', 'grudzień' ) ),
            'f' => array( 'dat' => 'n', 'str' => array( 'stycznia', 'lutego', 'marca', 'kwietnia', 'maja', 'czerwca', 'lipca', 'sierpnia', 'września', 'października', 'listopada', 'grudnia' ) )
    );
    if ( $pieces     = preg_split( '#[:/.\-, ]#', $format ) )
    {
      if ( $timestamp === null )
        $timestamp = time();

      foreach ( $pieces as $datepart )
      {
        if ( array_key_exists( $datepart, $to_convert ) )
          $replace[] = $to_convert[$datepart]['str'][( date( $to_convert[$datepart]['dat'], $timestamp ) - 1)];
        else
          $replace[] = date( $datepart, $timestamp );
      }
      $result = strtr( $format, array_combine( $pieces, $replace ) );
      return $result;
    }
  }

  public static function lang( $text )
  {
    global $lang;
    return $lang[$text] ? $lang[$text] : 'LANG-' . $text;
  }

  public static function array_cartesian_product( $input )
  {
    $result = array();

    foreach ($input as $key => $values)
    {
      if ( empty( $values ) )
        continue;

      if ( empty( $result ) )
      {
        foreach ( $values as $value )
        {
          $result[] = array( $key => $value );
        }
      }
      else
      {
        $append = array();

        foreach ( $result as &$product )
        {
          $product[$key] = array_shift( $values );
          $copy = $product;

          foreach ( $values as $item )
          {
            $copy[$key] = $item;
            $append[]   = $copy;
          }

          array_unshift( $values, $product[$key] );
        }

        $result = array_merge( $result, $append );
      }
    }

    return $result;
  }

  static public function normalize_decimal($val, int $precision = 2)
  {
    if ($val === null || $val === '') {
        return number_format(0, $precision, '.', '');
    }

    // 1) wstępne czyszczenie
    $s = (string)$val;
    $s = str_replace(["\xC2\xA0", ' ', '’', "'"], '', $s); // spacje (w tym NBSP) i apostrofy
    $s = preg_replace('/[^0-9.,\-]/', '', $s);             // zostaw tylko cyfry, . , i -

    // 2) ustalenie separatora dziesiętnego
    $lastDot   = strrpos($s, '.');
    $lastComma = strrpos($s, ',');

    if ($lastDot !== false && $lastComma !== false) {
        // oba występują – prawy znak traktujemy jako dziesiętny
        if ($lastDot > $lastComma) {
            $s = str_replace(',', '', $s);                 // , = tysiące
        } else {
            $s = str_replace('.', '', $s);                 // . = tysiące
            $s = str_replace(',', '.', $s);                // , = dziesiętny
        }
    } elseif ($lastComma !== false) {
        // tylko przecinek – traktuj jako dziesiętny
        $s = str_replace(',', '.', $s);
    } elseif (substr_count($s, '.') > 1) {
        // wiele kropek – ostatnia dziesiętna, pozostałe tysiące
        $pos = strrpos($s, '.');
        $s = str_replace('.', '', substr($s, 0, $pos)) . '.' . substr($s, $pos + 1);
    }
    // na tym etapie mamy opcjonalny '-' i co najwyżej jedną kropkę dziesiętną

    // 3) zaokrąglenie i normalizacja
    $rounded = round((float)$s, $precision);
    return number_format($rounded, $precision, '.', '');
  }

  public static function decimal( $val, $precision = 2, $dec_point = ',', $thousands_sep = ' ' )
  {
    return number_format( $val, $precision, $dec_point, $thousands_sep );
  }

  public static function get_new_version()
  {
    global $settings;

    if ( $version = self::get_session( 'new-version' ) )
      return $version;

    $version = 0;
    $versions = file_get_contents( 'https://shoppro.project-dc.pl/updates/versions.php?key=' . $settings['update_key'] );
    $versions = explode( PHP_EOL, $versions );
    foreach ( $versions as $key => $version_tmp )
    {
      $version_tmp = floatval( $version_tmp );
      if ( $version_tmp > $version and $version_tmp )
        $version = $version_tmp;
    }

    self::set_session( 'new-version', $version );

    return $version;
  }

  public static function get_version()
  {
    return (float) @file_get_contents( '../libraries/version.ini' );
  }

  public static function set_session( $var, $val )
  {
    $_SESSION[$var] = $val;
  }

  public static function get_session( $var )
  {
    return $_SESSION[$var];
  }

  public static function delete_session( $var )
  {
    unset( $_SESSION[$var] );
  }

  public static function get( $var, $clear = false )
  {
    if ( isset( $_POST[$var] ) )
    {
      if ( is_string( $_POST[$var] ) )
      {
        $value = $_POST[$var];

        if ( $clear )
        {
          $value = strip_tags( $value );
          $value = preg_replace( '/[\'\"\\\\]/i', '', $value );
        }

        return trim( $value );
      }
      else
        return $_POST[$var];
    }
    else
    {
      if ( isset( $_GET[$var] ) )
      {
        if ( is_string( $_GET[$var] ) )
          return trim( $_GET[$var] );
        else
          return $_GET[$var];
      }
    }
  }

  public static function set_message( $text )
  {
    self::set_session( 'message', $text );
  }

  public static function alert( $text )
  {
    self::set_session( 'alert', $text );
  }

  public static function error( $text )
  {
    self::set_session( 'error', $text );
  }

  public static function htacces( $dir = '../' )
  {
    global $mdb;

    $settings = ( new \Domain\Settings\SettingsRepository( $mdb ) )->allSettings( true );

    $url = preg_replace( '#^(http(s)?://)?w{3}\.#', '$1', $_SERVER['SERVER_NAME'] );

    $robots = 'User-agent: *' . PHP_EOL;
    $robots .= 'Allow: /' . PHP_EOL;

    $site_map = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
    $site_map .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . PHP_EOL;
    $site_map .= '<url>' . PHP_EOL;
    $site_map .= '<loc>https://' . $url . '</loc>' . PHP_EOL;
    $site_map .= '<lastmod>' . date( 'Y-m-d' ) . '</lastmod>' . PHP_EOL;
    $site_map .= '<changefreq>daily</changefreq>' . PHP_EOL;
    $site_map .= '<priority>1</priority>' . PHP_EOL;
    $site_map .= '</url>' . PHP_EOL;

    $htaccess_data = file_get_contents( $dir . 'libraries/htaccess.conf' );
    $htaccess_data = str_replace( '{PAGE}', $url, $htaccess_data );

    $results = $mdb -> select( 'pp_langs', [ 'id' ], [ 'status' => 1, 'ORDER' => [ 'o' => 'ASC' ] ] );
    if ( is_array( $results ) ) foreach ( $results as $row )
    {
      $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $row['id'] . '/$ index.php?a=change_language&id=' . $row['id'] . ' [L]';
    }

    //
    // INNE
    //
    $htaccess_data .= PHP_EOL;
    $htaccess_data .= 'RewriteRule ^newsletter/signin/$ index.php?module=newsletter&action=signin [L]' . PHP_EOL;
    $htaccess_data .= 'RewriteRule ^newsletter/confirm/hash=(.*)$ index.php?module=newsletter&action=confirm&hash=$1 [L]' . PHP_EOL;
    $htaccess_data .= 'RewriteRule ^newsletter/unsubscribe/hash=(.*)$ index.php?module=newsletter&action=unsubscribe&hash=$1 [L]' . PHP_EOL;

    //
    // PRODUCENCI
    //
    $htaccess_data .= 'RewriteRule ^producenci$ index.php?module=shop_producer&action=list&layout_id=' . \front\factory\Layouts::category_default_layout() . '&%{QUERY_STRING}  [L]' . PHP_EOL;

    $rows = $mdb -> select( 'pp_shop_producer', '*', [ 'status' => 1 ] );
    if ( self::is_array_fix( $rows ) ) foreach ( $rows as $row )
    {
      $htaccess_data .= 'RewriteRule ^producent/' . self::seo( $row['name'] ) . '$ index.php?module=shop_producer&action=products&producer_id=' . $row['id'] . '&layout_id=' . \front\factory\Layouts::category_default_layout() . '&%{QUERY_STRING} [L]' . PHP_EOL;
      $htaccess_data .= 'RewriteRule ^producent/' . self::seo( $row['name'] ) . '/([0-9]+)$ index.php?module=shop_producer&action=products&producer_id=' . $row['id'] . '&layout_id=' . \front\factory\Layouts::category_default_layout() . '&bs=$1&%{QUERY_STRING} [L]' . PHP_EOL;
    }

    $results = $mdb -> select( 'pp_langs', [ 'id', 'start' ], [ 'status' => 1, 'ORDER' => [ 'o' => 'ASC' ] ] );
    if ( is_array( $results ) ) foreach ( $results as $row )
    {
      !$row['start'] ? $language_link = $row['id'] . '/' : $language_link = '';

      $results2 = $mdb -> select( 'pp_shop_categories_langs', [ '[><]pp_shop_categories' => [ 'category_id' => 'id' ] ], [ 'seo_link', 'title', 'category_id' ], [ 'lang_id' => $row['id'], 'ORDER' => [ 'o' => 'ASC' ] ] );
      if ( is_array( $results2 ) ) foreach ( $results2 as $row2 )
      {
        if ( $row2['title'] )
        {
          $site_map .= '<url>' . PHP_EOL;
          if ( $row2['seo_link'] )
            $site_map .= '<loc>https://' . $url . '/' . $language_link . self::seo( $row2['seo_link'] ) . '</loc>' . PHP_EOL;
          else
            $site_map .= '<loc>https://' . $url . '/' . $language_link . 'k-' . $row2['category_id'] . '-' . self::seo( $row2['title'] ) . '</loc>' . PHP_EOL;
          $site_map .= '<lastmod>' . date( 'Y-m-d' ) . '</lastmod>' . PHP_EOL;
          $site_map .= '<changefreq>daily</changefreq>' . PHP_EOL;
          $site_map .= '<priority>1</priority>' . PHP_EOL;
          $site_map .= '</url>' . PHP_EOL;

          if ( $row2['seo_link'] )
          {
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '$ index.php?category=' . $row2['category_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '/([0-9]+)$ index.php?category=' . $row2['category_id'] . '&lang=' . $row['id'] . '&bs=$1&%{QUERY_STRING} [L]';
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '/1$ ' . $language_link . self::seo( $row2['seo_link'] ) . ' [R=301,L]';
          }
          else
          {
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 'k-' . $row2['category_id'] . '-' . self::seo( $row2['title'] ) . '$ index.php?category=' . $row2['category_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 'k-' . $row2['category_id'] . '-' . self::seo( $row2['title'] ) . '/([0-9]+)$ index.php?category=' . $row2['category_id'] . '&lang=' . $row['id'] . '&bs=$1&%{QUERY_STRING} [L]';
            $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 'k-' . $row2['category_id'] . '-' . self::seo( $row2['title'] ) . '/1$ ' . $language_link . 'k-' . $row2['category_id'] . '-' . self::seo( $row2['title'] ) . ' [R=301,L]';
          }
        }
      }
    }

    $results = $mdb -> select( 'pp_langs', [ 'id', 'start' ], [ 'status' => 1, 'ORDER' => [ 'o' => 'ASC' ] ] );
    if ( is_array( $results ) )
    {
      foreach ( $results as $row )
      {
        !$row['start'] ? $language_link = $row['id'] . '/' : $language_link = '';

        $results2 = $mdb -> select( 'pp_shop_products_langs', [ '[><]pp_shop_products' => [ 'product_id' => 'id' ] ], [ 'seo_link', 'name', 'product_id' ], [ 'lang_id' => $row['id'], 'ORDER' => [ 'name' => 'ASC' ] ] );
        if ( is_array( $results2 ) )
        {
          foreach ( $results2 as $row2 )
          {
            $mdb -> delete( 'pp_routes', [ 'AND' => [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'] ] ] );

            if ( $row2['name'] )
            {
              $site_map .= '<url>' . PHP_EOL;
              if ( $row2['seo_link'] )
                $site_map .= '<loc>https://' . $url . '/' . $language_link . self::seo( $row2['seo_link'] ) . '</loc>' . PHP_EOL;
              else
                $site_map .= '<loc>https://' . $url . '/' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '</loc>' . PHP_EOL;
              $site_map .= '<lastmod>' . date( 'Y-m-d' ) . '</lastmod>' . PHP_EOL;
              $site_map .= '<changefreq>daily</changefreq>' . PHP_EOL;
              $site_map .= '<priority>1</priority>' . PHP_EOL;
              $site_map .= '</url>' . PHP_EOL;

              if ( $row2['seo_link'] )
              {
                $pattern = '^' . $language_link . self::seo( $row2['seo_link'] ) . '$';
                $destination = 'index.php?product=' . $row2['product_id'];

                $mdb -> insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => $pattern, 'destination' => $destination ] );

                $pattern = '^' . $language_link . self::seo( $row2['seo_link'] ) . '/([0-9-]+)$';
                $destination = 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1';

                $mdb -> insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => $pattern, 'destination' => $destination ] );
              }
              else
              {
                $pattern = '^' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '$';
                $destination = 'index.php?product=' . $row2['product_id'];

                $mdb -> insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => $pattern, 'destination' => $destination ] );

                $pattern = '^' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '/([0-9-]+)$';
                $destination = 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1';

                $mdb -> insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => $pattern, 'destination' => $destination ] );
              }
            }
          }
        }
      }
    }

    $results = $mdb -> select( 'pp_langs', [ 'id', 'start' ], [ 'status' => 1, 'ORDER' => [ 'o' => 'ASC' ] ] );
    if ( is_array( $results ) )
      foreach ( $results as $row )
      {
        ( !$row['start'] and count( $results ) > 1 ) ? $language_link = $row['id'] . '/' : $language_link = '';

        $results2 = $mdb -> select( 'pp_pages_langs', [ '[><]pp_pages' => [ 'page_id' => 'id' ] ], [ 'seo_link', 'title', 'page_id', 'noindex', 'start', 'link', 'page_type' ], [ 'lang_id' => $row['id'], 'ORDER' => [ 'start' => 'DESC', 'o' => 'ASC' ] ] );
        if ( is_array( $results2 ) )
          foreach ( $results2 as $row2 )
          {
            if ( $row2['title'] and $row2['page_type'] != 3 and $row2['page_type'] != 5 )
            {
              if ( !$row2['noindex'] )
              {
                $site_map .= '<url>' . PHP_EOL;
                if ( $row2['seo_link'] )
                  $site_map .= '<loc>https://' . $url . '/' . self::seo( $row2['seo_link'] ) . '</loc>' . PHP_EOL;
                else
                  $site_map .= '<loc>https://' . $url . '/s-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '</loc>' . PHP_EOL;
                $site_map .= '<lastmod>' . date( 'Y-m-d' ) . '</lastmod>' . PHP_EOL;
                $site_map .= '<changefreq>daily</changefreq>' . PHP_EOL;
                $site_map .= '<priority>1</priority>' . PHP_EOL;
                $site_map .= '</url>' . PHP_EOL;
              }
              else if ( $row2['noindex'] and $row2['seo_link'] )
              {
                $robots .= 'User-agent: GoogleBot' . PHP_EOL;
                $robots .= 'Disallow: /' . $row2['seo_link'] . PHP_EOL;
              }

              if ( $row2['start'] )
              {
                if ( $row2['seo_link'] )
                {
                  $htaccess_data .= PHP_EOL . 'RewriteCond %{REQUEST_URI} ^/' . self::seo( $row2['seo_link'] ) . '$';
                  $htaccess_data .= PHP_EOL . 'RewriteRule ^(.*)$ http://www.' . $url . '/' . $language_link . ' [R=permanent,L]';
                  $htaccess_data .= PHP_EOL . 'RewriteCond %{REQUEST_URI} ^/' . self::seo( $row2['seo_link'] ) . '-1$';
                  $htaccess_data .= PHP_EOL . 'RewriteRule ^(.*)$ http://www.' . $url . '/' . $language_link . ' [R=permanent,L]';
                }
                else
                {
                  $htaccess_data .= PHP_EOL . 'RewriteCond %{REQUEST_URI} ^/s-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '$';
                  $htaccess_data .= PHP_EOL . 'RewriteRule ^(.*)$ http://www.' . $url . '/' . $language_link . ' [R=permanent,L]';

                  $htaccess_data .= PHP_EOL . 'RewriteCond %{REQUEST_URI} ^/s-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '-1$';
                  $htaccess_data .= PHP_EOL . 'RewriteRule ^(.*)$ http://www.' . $url . '/' . $language_link . ' [R=permanent,L]';
                }

                $htaccess_data .= PHP_EOL . 'RewriteRule ^$ index.php?a=page&id=' . $row2['page_id'] . '&lang=' . $row['id'] . ' [L]';
              }

              if ( $row2['seo_link'] )
              {
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '$ index.php?a=page&id=' . $row2['page_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '/([0-9]+)$ index.php?a=page&id=' . $row2['page_id'] . '&lang=' . $row['id'] . '&bs=$1&%{QUERY_STRING} [L]';
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '/1$ ' . $language_link . self::seo( $row2['seo_link'] ) . ' [R=301,L]';
              }
              else
              {
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 's-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '$ index.php?a=page&id=' . $row2['page_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 's-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '/([0-9]+)$ index.php?a=page&id=' . $row2['page_id'] . '&lang=' . $row['id'] . '&bs=$1&%{QUERY_STRING} [L]';
                $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 's-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . '/1$ ' . $language_link . 's-' . $row2['page_id'] . '-' . self::seo( $row2['title'] ) . ' [R=301,L]';
              }
            }
          }

        $results2 = $mdb -> select( 'pp_articles_langs', [ '[><]pp_articles' => [ 'article_id' => 'id' ] ], [ 'seo_link', 'title', 'article_id', 'noindex', 'copy_from' ], [ 'AND' => [ 'status' => 1, 'lang_id' => $row['id'], 'block_direct_access' => 0 ] ] );
        if ( is_array( $results2 ) )
          foreach ( $results2 as $row2 )
          {
            if ( $row2['copy_from'] != null )
            {
              $results_tmp      = $mdb -> get( 'pp_articles_langs', [
                      'seo_link',
                      'title'
                      ], [
                      'AND' => [
                              'article_id' => $row2['article_id'],
                              'lang_id'    => $row2['copy_from']
                      ]
                      ] );
              $row2['seo_link'] = $results_tmp['seo_link'];
              $row2['title']    = $results_tmp['title'];
            }

            if ( !$row2['noindex'] )
            {
              $site_map .= '<url>' . PHP_EOL;
              if ( $row2['seo_link'] )
                $site_map .= '<loc>https://' . $url . '/' . self::seo( $row2['seo_link'] ) . '</loc>' . PHP_EOL;
              else
                $site_map .= '<loc>https://' . $url . '/a-' . $row2['article_id'] . '-' . self::seo( $row2['title'] ) . '</loc>' . PHP_EOL;
              $site_map .= '<lastmod>' . date( 'Y-m-d' ) . '</lastmod>' . PHP_EOL;
              $site_map .= '<changefreq>daily</changefreq>' . PHP_EOL;
              $site_map .= '<priority>1</priority>' . PHP_EOL;
              $site_map .= '</url>' . PHP_EOL;
            }
            else if ( $row2['noindex'] and $row2['seo_link'] )
            {
              $robots .= 'User-agent: GoogleBot' . PHP_EOL;
              $robots .= 'Disallow: /' . $row2['seo_link'] . PHP_EOL;
            }

            if ( $row2['seo_link'] )
              $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . self::seo( $row2['seo_link'] ) . '$ index.php?article=' . $row2['article_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
            else if ( $row2['title'] != null )
              $htaccess_data .= PHP_EOL . 'RewriteRule ^' . $language_link . 'a-' . $row2['article_id'] . '-' . self::seo( $row2['title'] ) . '$ index.php?article=' . $row2['article_id'] . '&lang=' . $row['id'] . '&%{QUERY_STRING} [L]';
          }
      }

    $results       = $mdb -> get( 'pp_settings', 'value', [ 'param' => 'htaccess' ] );
    if ( $results )
      $htaccess_data .= PHP_EOL . $results;

    $results = $mdb -> get( 'pp_settings', 'value', [ 'param' => 'robots' ] );
    if ( $results )
      $robots  .= PHP_EOL . $results;

    $site_map .= '</urlset>';

    /* cache */
    if ( $settings['htaccess_cache'] )
    {
      $htaccess_data = str_replace( '{HTACCESS_CACHE}',
              '<IfModule mod_deflate.c>' . PHP_EOL
              . 'AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/css text/javascript application/javascript application/x-javascript' . PHP_EOL
              . '</IfModule>' . PHP_EOL
              . '<IfModule mod_headers.c>' . PHP_EOL
              . 'Header set Access-Control-Allow-Origin "*"' . PHP_EOL
              . '</IfModule>' . PHP_EOL
              . '<IfModule mod_expires.c>' . PHP_EOL
              . 'ExpiresActive on' . PHP_EOL
              . 'ExpiresDefault                                      "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType text/css                              "access plus 1 year"' . PHP_EOL
              . 'ExpiresByType application/json                      "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType application/xml                       "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType text/xml                              "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType image/x-icon                          "access plus 1 week"' . PHP_EOL
              . 'ExpiresByType text/x-component                      "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType text/html                             "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType application/javascript                "access plus 1 year"' . PHP_EOL
              . 'ExpiresByType application/x-web-app-manifest+json   "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType text/cache-manifest                   "access plus 0 seconds"' . PHP_EOL
              . 'ExpiresByType audio/ogg                             "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType image/gif                             "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType image/jpeg                            "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType image/png                             "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType video/mp4                             "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType video/ogg                             "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType video/webm                            "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType application/atom+xml                  "access plus 1 hour"' . PHP_EOL
              . 'ExpiresByType application/rss+xml                   "access plus 1 hour"' . PHP_EOL
              . 'ExpiresByType application/font-woff                 "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType application/vnd.ms-fontobject         "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType application/x-font-ttf                "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType font/opentype                         "access plus 1 month"' . PHP_EOL
              . 'ExpiresByType image/svg+xml                         "access plus 1 month"' . PHP_EOL
              . '</IfModule>'
              , $htaccess_data );
    }
    else
    {
      $htaccess_data = str_replace( '{HTACCESS_CACHE}',
              '<IfModule mod_headers.c>' . PHP_EOL
              . 'Header set Cache-Control "no-cache, no-store, must-revalidate"' . PHP_EOL
              . 'Header set Pragma "no-cache"' . PHP_EOL
              . 'Header set Expires 0' . PHP_EOL
              . '</IfModule>',
            $htaccess_data );
    }

    $htaccess_data .= PHP_EOL;
    $htaccess_data .= 'RewriteCond %{REQUEST_FILENAME} !-f' . PHP_EOL;
    $htaccess_data .= 'RewriteCond %{REQUEST_FILENAME} !-d' . PHP_EOL;
    $htaccess_data .= 'RewriteRule ^ index.php [L]';

    // Niektore hostingi blokuja zmiane wersji PHP przez .htaccess.
    // Automatycznie komentujemy niedozwolone dyrektywy, aby generowany plik byl kompatybilny.
    $htaccess_data = preg_replace( '/^(\\s*)(AddHandler|SetHandler|ForceType)\\b/im', '$1# $2', $htaccess_data );

    $fp = fopen( $dir . '.htaccess', 'w' );
    fwrite( $fp, $htaccess_data );
    fclose( $fp );

    $fp = fopen( $dir . 'sitemap.xml', 'w' );
    fwrite( $fp, $site_map );
    fclose( $fp );

    $fp = fopen( $dir . 'robots.txt', 'w' );
    fwrite( $fp, $robots );
    fclose( $fp );
  }



  public static function seo( $val, $delete_rhombs = false )
  {
    $array_rep1 = array('*', '_', ' ', '+', '"', "'", '?', '-', ',', '!', '~', '<', '>', '@', '#', '$', '%', '^', '&', '*' . '(', ')' . '-', '=', '\\', '|', '[', ']', ':', '(', ')');
    $array_rep2 = array('-', '-', '-', '-', '', '', '', '-', '-', '', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '', '-', '-', '-', '-', '-', '-', '-', '-');
    $val = self::noPl($val);
    $val = str_replace($array_rep1, $array_rep2, $val);
    if ($delete_rhombs)
      $val = str_replace('/', '', $val);

    $val = strtolower($val);
    $val = preg_replace('/(-){2,}/', '-', $val);
    $val = ltrim($val, '-');
    $val = rtrim($val, '-');
    return $val;
  }

  public static function noPL($string)
  {
    $chars = array( // Decompositions for Latin-1 Supplement chr(195).chr(128)=> 'A', chr(195).chr(129) => 'A',
      chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A',
      chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A',
      chr(195) . chr(135) => 'C', chr(195) . chr(136) => 'E',
      chr(195) . chr(137) => 'E', chr(195) . chr(138) => 'E',
      chr(195) . chr(139) => 'E', chr(195) . chr(140) => 'I',
      chr(195) . chr(141) => 'I', chr(195) . chr(142) => 'I',
      chr(195) . chr(143) => 'I', chr(195) . chr(145) => 'N',
      chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O',
      chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O',
      chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U',
      chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U',
      chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y',
      chr(195) . chr(159) => 's', chr(195) . chr(160) => 'a',
      chr(195) . chr(161) => 'a', chr(195) . chr(162) => 'a',
      chr(195) . chr(163) => 'a', chr(195) . chr(164) => 'a',
      chr(195) . chr(165) => 'a', chr(195) . chr(167) => 'c',
      chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e',
      chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e',
      chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i',
      chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i',
      chr(195) . chr(177) => 'n', chr(195) . chr(178) => 'o',
      chr(195) . chr(179) => 'o', chr(195) . chr(180) => 'o',
      chr(195) . chr(181) => 'o', chr(195) . chr(182) => 'o',
      chr(195) . chr(182) => 'o', chr(195) . chr(185) => 'u',
      chr(195) . chr(186) => 'u', chr(195) . chr(187) => 'u',
      chr(195) . chr(188) => 'u', chr(195) . chr(189) => 'y',
      chr(195) . chr(191) => 'y',
      // Decompositions for Latin Extended-A
      chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a',
      chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a',
      chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a',
      chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c',
      chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c',
      chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c',
      chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c',
      chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd',
      chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd',
      chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e',
      chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e',
      chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e',
      chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e',
      chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e',
      chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g',
      chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g',
      chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g',
      chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g',
      chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h',
      chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h',
      chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i',
      chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i',
      chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i',
      chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i',
      chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i',
      chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij',
      chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j',
      chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k',
      chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L',
      chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L',
      chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L',
      chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L',
      chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L',
      chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N',
      chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N',
      chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N',
      chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N',
      chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N',
      chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o',
      chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o',
      chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o',
      chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe',
      chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r',
      chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r',
      chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r',
      chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's',
      chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's',
      chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's',
      chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's',
      chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't',
      chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't',
      chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't',
      chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u',
      chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u',
      chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u',
      chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u',
      chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u',
      chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u',
      chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w',
      chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y',
      chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z',
      chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z',
      chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z',
      chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's'
    );

    $string = strtr($string, $chars);

    $table = array(
      "А" => "a", "Б" => "b", "В" => "v", "Г" => "g", "Д" => "d",
      "Е" => "e", "Ё" => "yo", "Ж" => "zh", "З" => "z", "И" => "i",
      "Й" => "j", "К" => "k", "Л" => "l", "М" => "m", "Н" => "n",
      "О" => "o", "П" => "p", "Р" => "r", "С" => "s", "Т" => "t",
      "У" => "u", "Ф" => "f", "Х" => "kh", "Ц" => "ts", "Ч" => "ch",
      "Ш" => "sh", "Щ" => "sch", "Ъ" => "", "Ы" => "y", "Ь" => "",
      "Э" => "e", "Ю" => "yu", "Я" => "ya", "а" => "a", "б" => "b",
      "в" => "v", "г" => "g", "д" => "d", "е" => "e", "ё" => "yo",
      "ж" => "zh", "з" => "z", "и" => "i", "й" => "j", "к" => "k",
      "л" => "l", "м" => "m", "н" => "n", "о" => "o", "п" => "p",
      "р" => "r", "с" => "s", "т" => "t", "у" => "u", "ф" => "f",
      "х" => "kh", "ц" => "ts", "ч" => "ch", "ш" => "sh", "щ" => "sch",
      "ъ" => "", "ы" => "y", "ь" => "", "э" => "e", "ю" => "yu",
      "я" => "ya", " " => "-", "." => "", "," => "",
      ":" => "", ";" => "", "—" => "", "–" => "-"
    );

    $string = strtr($string, $table);

    return $string;
  }

  public static function delete_dir( $dir )
  {
    if ( is_file( $dir ) )
      return @unlink( $dir );

    else if ( is_dir( $dir ) )
    {
      $scan = glob( rtrim( $dir, '/' ) . '/*' );

      if ( is_array( $scan ) )
        foreach ( $scan as $index => $path )
          self::delete_dir( $path );

      if ( is_dir( $dir ) && ( ( $files = @scandir( $dir ) ) && count( $files ) <= 2 ) )
        return @rmdir( $dir );
    }
  }

  public static function email_check( $email )
  {
    return filter_var( $email, FILTER_VALIDATE_EMAIL );
  }

  public static function send_email( $email, $subject, $text, $replay = '', $file = '' )
  {
    global $settings;

    if ( self::email_check( $email ) and $subject )
    {
      $mail              = new \PHPMailer();
      $mail -> IsSMTP();
      $mail -> SMTPAuth    = true;
      $mail -> Host        = $settings['email_host'];
      $mail -> Port        = $settings['email_port'];
      $mail -> Username    = $settings['email_login'];
      $mail -> Password    = $settings['email_password'];
      $mail -> CharSet     = "UTF-8";
      $mail -> SMTPOptions = array(
              'ssl' => array(
                      'verify_peer'       => false,
                      'verify_peer_name'  => false,
                      'allow_self_signed' => true
              )
      );

      if ( self::email_check( $replay ) )
      {
        $mail -> AddReplyTo( $replay, $replay );
        $mail -> SetFrom( $replay, $replay );
      }
      else
      {
        $mail -> AddReplyTo( $settings['contact_email'], $settings['firm_name'] );
        $mail -> SetFrom( $settings['contact_email'], $settings['firm_name'] );
      }
      $mail -> AddAddress( $email, '' );
      $mail -> Subject = $subject;
      $mail -> Body    = $text;
      if ( is_array( $file ) )
      {
        foreach ( $file as $file_tmp )
        {
          if ( file_exists( $file_tmp ) )
            $mail -> AddAttachment( $file_tmp );
        }
      }
      else
      {
        if ( file_exists( $file ) )
          $mail -> AddAttachment( $file );
      }
      $mail -> IsHTML( true );
      return $mail -> Send();
    }
    return false;
  }
}

