<?php
/**
## Version: 2.1 -- Date: 05-SEP-2019 -- Added version information and revision history.
**/
class SableGeneralFunctions {
  public function __construct() {}
  public function __destruct() {}

  public static function revertToLoginPage( $msg = 'Please log in to continue.' ) {
    /*
    	$_SESSION['revert'] will only be used in sable_footer.php to initiate a js call to revert to the login page. There
    	it will immediately unset the session variable for reuse.
    */
    //if (isset($_SESSION['current_dir']))
    if ( SableSystem::loggedIn() ) {
      SableSystem::logout();
      $_SESSION[ 'revert' ][ 'url' ] = SableSystem::getSableLinkPath( 'login/' );
      $_SESSION[ 'revert' ][ 'msg' ] = $msg;
      $_SESSION[ 'caller' ][ 'args' ][ 0 ] = $_SESSION[ 'revert' ][ 'url' ];
    } else {
      try {
        if ( !headers_sent() )
          header( 'Location: ' . SABLE_URL_ROOT . 'signin' );
        else {
          include_once( SABLE_WORKING_PATH . 'login/index.php' );
          include_once( SABLE_INCLUDES_PATH . 'sable_footer.php' );
          exit;
        }
      } catch ( Exception $e ) {
        if ( SABLE_ENABLE_ERRORS )echo 'Exception performing log out: ' . $e->getMessage();

      }
    }
  }

  public static function divertFromPage( $url = '/', $msg = 'Access prohibited.', $seo = false ) {
    /*
    	$_SESSION['revert'] will only be used in sable_footer.php to initiate a js call to revert to the login page. There
    	it will immediately unset the session variable for reuse.
    */
    $path = SableSystem::loggedIn() ? SableSystem::getSableLinkPath( $url ) : $url;
    $_SESSION[ 'revert' ][ 'url' ] = $seo ? $url : $path;
    $_SESSION[ 'revert' ][ 'msg' ] = $msg;
    //self::callPage($_SESSION['revert']['url']);
    $_SESSION[ 'caller' ][ 'args' ][ 0 ] = $url;
  }

  public static function getModuleJS( $module ) {
    /*
    $themePathJs		= SABLE_THEME_WORKING_PATH.$module.'/'.$module.'.js';
    $themeLocationJs	= SABLE_THEME_ROOT.$module.'/'.$module.'.js';
    $sableLocationJs	= SABLE_URL_ROOT.$module.'/'.$module.'.js';
    if (file_exists($themePathJs)) return $themeLocationJs; else return $sableLocationJs;
    */
    $sableLocationJs = SABLE_URL_ROOT . $module . '/' . $module . '.js?v=' . SABLE_VERSION;
    return $sableLocationJs;
  }
  public static function printModuleJS( $module ) {
    echo( self::getModuleJS( $module ) );
  }
  public static function getImagePath( $imageName ) {
    echo( SABLE_IMAGES_PATH . $imageName );
  }

  public static function setCoyTitle() {
    $coyTitle = isset( $_SESSION[ 'site' ] ) ? $_SESSION[ 'site' ][ 'site_title' ] : SABLE_SITE_TITLE;
    return $coyTitle;
  }

  /*
  Function 'getRealIpAddr' tries to obtain the IP address of the client machine, rather
  than from the ISP. This is to try and maintain a unique audit trail. The users IP
  address is stored on the database for each session whenever a session is created. It
  is obviously removed when the session is destroyed.
  */
  public static function getRealIpAddr() {
    $client = @$_SERVER[ 'HTTP_CLIENT_IP' ];
    $forward = @$_SERVER[ 'HTTP_X_FORWARDED_FOR' ];
    $remote = @$_SERVER[ 'REMOTE_ADDR' ];

    if ( filter_var( $client, FILTER_VALIDATE_IP ) ) {
      $ip = $client;
    } elseif ( filter_var( $forward, FILTER_VALIDATE_IP ) ) {
      $ip = $forward;
    }
    else {
      $ip = $remote;
    }
    return $ip;
  } //getRealIpAddr()

  public static function getLocationInfoByIp( $ip = "" ) {
    $result = array( 'country' => '', 'city' => '' );
    if ( empty( $ip ) )$ip = self::getRealIpAddr();
    $ip_data = @json_decode( file_get_contents( "http://www.geoplugin.net/json.gp?ip=" . $ip ) );
    if ( $ip_data && $ip_data->geoplugin_countryName != null ) {
      global $sableDB;
      $row = $sableDB->getRow( "select * from country where country_iso = '" . $ip_data->geoplugin_countryCode . "'" );
      $result = $row;
      //$result['country'] = $ip_data->geoplugin_countryCode;
      $result[ 'city' ] = $ip_data->geoplugin_city;

    }
    return $result; //http://www.geoplugin.net/json.gp?ip=105.224.140.13
  }

  public static function getCallingSitePrefix() {
    $res = isset( $_SESSION[ 'site' ] ) ? $_SESSION[ 'site' ][ 'site_url' ] : SABLE_WORKING_PATH;
    return $res;
  }

  public static function callDataList() {
    require( SABLE_WORKING_PATH . 'list/index.php' );
  }

  /*
  Function 'removeSpaces' removes the spaces from a given string and returns the resultant string.
  */
  public static function removeSpaces( $s ) {
    $newstr = null;
    for ( $i = 0; $i < strlen( $s ); $i++ ) {
      $oldstr = substr( $s, $i, 1 );
      if ( $oldstr == ' ' ) {} //end-if
      else {
        $newstr .= $oldstr;
      } //end-else
    } //end-for
    return $newstr;
  }

  public static function replaceWhitespace( $source, $replaceWith = "" ) {
    $ln = $source;
    $ln = str_replace( " ", $replaceWith, $ln ); //space
    $ln = str_replace( "\t", $replaceWith, $ln ); //tab
    $ln = str_replace( "\n", $replaceWith, $ln ); //new line
    $ln = str_replace( "\r", $replaceWith, $ln ); //carriage return
    $ln = str_replace( "\0", $replaceWith, $ln ); //NULL Byte
    $ln = str_replace( "\x0B", $replaceWith, $ln ); // (a vertical tab)
    return $ln;
  }

  public static function replaceSpaces( & $subject, $with ) {
    $subject = str_replace( ' ', $with, $subject );
  }

  public static function hideEmail( $email, $display = "", $subject = "" ) //from: http://www.maurits.vdschee.nl/php_hide_email/
  {
    $character_set = '+-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
    $key = str_shuffle( $character_set );
    $cipher_text = '';
    $email = $email;

    $dp = "";
    if ( !empty( $display ) )$dp = $display;
    else $dp = $email;

    $sb = "";
    if ( !empty( $subject ) )$sb = '?subject=' . $subject;

    $id = 'e' . rand( 1, 999999999 );
    for ( $i = 0; $i < strlen( $email ); $i += 1 )$cipher_text .= $key[ strpos( $character_set, $email[ $i ] ) ];
    $script = 'var a="' .
    $key . '";var b=a.split("").sort().join("");var c="' .
    $cipher_text . '";var d="";';
    $script .= 'for(var e=0;e<c.length;e++)d+=b.charAt(a.indexOf(c.charAt(e)));';
    //	if (empty($display)) 
    //		$script.= 'document.getElementById("'.$id.'").innerHTML="<a class=\"link_contrast\" href=\\"mailto:"+d+"\\">"+d+"</a>"';
    //	else
    $script .= 'document.getElementById("' . $id . '").innerHTML="<a class=\"link_contrast\" href=\\"mailto:"+d+"' . $sb . '\\">' . $dp . '</a>"';
    $script = "eval(\"" . str_replace( array( "\\", '"' ), array( "\\\\", '\"' ), $script ) . "\")";
    $script = '<script>/*<![CDATA[*/' . $script . '/*]]>*/</script>';
    return '<span id="' . $id . '">[javascript protected email address]</span>' . $script;
  }

  public static function strposa( $haystack, $needle ) {
    if ( !is_array( $needle ) )$needle = array( $needle );
    foreach ( $needle as $query ) {
      if ( strpos( $haystack, $query ) !== false ) return true; // stop on first true result
    }
    return false;
  }

  public static function fileIsImage( $fileName ) {
    $ext = strtolower( self::getFileExtension( $fileName ) );
    $ok = ( $ext === 'gif' ) || ( $ext === 'png' ) || ( $ext === 'jpg' ) || ( $ext === 'jpeg' );
    return $ok;
  }

  public static function getFileExtension( $fileName ) {
    /*
    	This function intends to extract only return the file exension (if applicable) with the . - e.g. .php
    */
    $path = pathinfo( $fileName );
    return isset( $path[ 'extension' ] ) ? $path[ 'extension' ] : '';
  }

  public static function getFileIcon( $fileName, $size = '32', $id = '', $responsive = false ) {
    if ( !is_file( $fileName ) )SableSystem::convertURLPathToWorkPath( $fileName );
    $ext = self::getFileExtension( $fileName );
    $icon = SableSystem::getSableImgPath( 'filetypes/' . $ext . '.png' );
    return SableSystem::getImgHTML( $icon, $size, $id, $responsive );
    //		return $icon;
  }

  public static function extractFilePath( $fileName ) {
    /*
    	This function intends to extract only the file path of a full file name, for example:
    	extractFilePath('/vol1/home-hosting/spitronics.co.za/html2/index.php') ==> '/vol1/home-hosting/spitronics.co.za/html2/'
    */
    $path = pathinfo( $fileName );
    if ( isset( $path[ 'extension' ] ) ) {
      $dir = $path[ 'dirname' ];
      //$dir = str_replace('//', '/', $dir);
    } else $dir = $fileName;
    return $dir;
  }

  public static function extractDirName( $path ) //login/index.php
  {
    //SableDebug::debug($path);
    $res = str_replace( SABLE_URL_ROOT, '', $path );
    $res = str_replace( SABLE_WORKING_PATH, '', $res );
    $f = self::extractFileName( $res );
    $res = str_replace( $f, '', $res );

    $res = str_replace( SABLE_THEME_PATH, '', $res );
    $res = str_replace( SABLE_THEME_NAME, '', $res );

    $res = ltrim( $res, '/' );
    $res = rtrim( $res, '/' );

    //$res = str_replace('/', '', $res); //---> we could have /media/images/profile as a result....
    return $res;
  }

  public static function extractFileName( $fileName ) {
    /*
    	This function intends to extract only the file name of a full file name, for example:
    	etractFilePath('/vol1/home-hosting/spitronics.co.za/html2/index.php') ==> 'index.php'
    */
    $path = pathinfo( $fileName );
    if ( isset( $path[ 'basename' ] ) ) return $path[ 'basename' ];
    else return $fileName;
  }

  public static function addYouTubeVideo( $link, $width, $height ) {
    //link must be with parameters, e.g.: https://www.youtube.com/embed/GUqCR0aENd0?&loop=1
    return '<iframe width="' . $width . '" height="' . $height . '" src="' . $link . '"></iframe>';
  }

  public static function embedYouTubeVideo( $link, $width, $height ) {
    $url = $link; //"http://www.youtube.com/watch?v=C4kxS1ksqtw&feature=relate";
    parse_str( parse_url( $url, PHP_URL_QUERY ), $vars );
    $id = $vars[ 'v' ]; // Output: C4kxS1ksqtw as per example above:
    $link = 'https://www.youtube.com/embed/' . $id . '?&loop=1';
    return self::addYouTubeVideo( $link, $width, $height );
  }

  public static function getFormattedModuleName( $module ) {
    $tmp = explode( '_', $module );
    $ttl = '';
    for ( $i = 0; $i < sizeof( $tmp ); $i++ )$tmp[ $i ] = ucfirst( $tmp[ $i ] );
    return implode( ' ', $tmp );
  }

  public static function getClassNameFormat( $module, $connector = '-' ) {
    $tmp = strtolower( $module );
    $tmp = str_replace( ' ', $connector, $tmp );
    $tmp = str_replace( '_', $connector, $tmp );
    $tmp = str_replace( '.', $connector, $tmp );
    $tmp = str_replace( ',', $connector, $tmp );
    $tmp = str_replace( '----', $connector, $tmp );
    $tmp = str_replace( '---', $connector, $tmp );
    $tmp = str_replace( '--', $connector, $tmp );
    return $tmp;
  }

  private static function verifyURL( $url ) {
    //SableDebug::debug($prtcl);
    if ( function_exists( 'curl_version' ) ) //check if CURL is installed
    {
      //SableDebug::debugout('curl is installed.');			
      $c = @curl_init();
      @curl_setopt( $c, CURLOPT_HEADER, TRUE );
      @curl_setopt( $c, CURLOPT_NOBODY, TRUE );
      @curl_setopt( $c, CURLOPT_FOLLOWLOCATION, FALSE );
      @curl_setopt( $c, CURLOPT_SSL_VERIFYPEER, FALSE );
      @curl_setopt( $c, CURLOPT_SSL_VERIFYHOST, TRUE );
      @curl_setopt( $c, CURLOPT_RETURNTRANSFER, TRUE );
      @curl_setopt( $c, CURLOPT_URL, $url );
      @curl_exec( $c );
      $status = curl_getinfo( $c );
      @curl_close( $c );
      return $status[ 'http_code' ] == 200;
    } else {
      //SableDebug::debugout('curl NOT installed.');
      $h = get_headers( $url );
      $status = array();
      $prtcl = strpos( $url, 'https' ) === false ? 'HTTP' : 'HTTPS';
      preg_match( '/' . $prtcl . '\/.* ([0-9]+) .*/', $h[ 0 ], $status );
      return ( $status[ 1 ] == 200 );
    }
  }

  public static function checkURLExists( $url ) {
    //first check the current protocol:
    $legit = self::verifyURL( $url );
    if ( !$legit ) {
      $priorProtocol = strpos( $url, 'https' ) ? 'https' : 'http';
      $newProtocol = strpos( $url, 'https' ) ? 'http' : 'https';
      $url = str_replace( $priorProtocol, $newProtocol, $url );
      $legit = self::verifyURL( $url );
    }
    return $legit;
  }

  public static function getGenderFromRSAId( $id ) {
    return ( ( $id[ 6 ] * 1 ) > 4 ) ? 1 : 0;
  } //True = MALE, False = FEMALE

  public static function getBirthDateFromRSAId( $id ) {
    $validID = SableValidationFunctions::validateIDNo( $id, '', true );
    if ( $validID ) {
      $yy = substr( $id, 0, 2 ); //76
      $yyyy = intval( ( intval( $yy ) < 29 ) ? '20' . $yy : '19' . $yy );
      $mm = substr( $id, 2, 2 ); //09
      $dd = substr( $id, 4, 2 ); //22

    } else {
      //just default to 1 Jan 1970
      $yyyy = 1970;
      $mm = 1;
      $dd = 1;
    }

    $ts = mktime( 0, 0, 0, $mm, $dd, $yyyy );
    return $ts;
  }

  public static function getDateTimeFromDBTimestamp( $format, $fieldValue ) {
    return date( $format, strtotime( $fieldValue ) );
  }

  public static function getFullUserName( $withTitle = false ) {
    $usrName = isset( $_SESSION[ 'user' ][ 'user_name' ] ) ? $_SESSION[ 'user' ][ 'user_name' ] : 'Unknown';
    $usrSurname = isset( $_SESSION[ 'user' ][ 'user_surname' ] ) ? $_SESSION[ 'user' ][ 'user_surname' ] : '';
    $usrTitle = isset( $_SESSION[ 'user' ][ 'user_title' ] ) ? $_SESSION[ 'user' ][ 'user_title' ] : '';
    $name = $withTitle ? $usrTitle . ' ' . $usrName . ' ' . $usrSurname: $usrName . ' ' . $usrSurname;
    return $name;
  }

  public static function printFullUserName( $withTitle = false ) {
    $name = self::getFullUserName( $withTitle );
    echo( $name );
  }

  public static function getCompanyName() {
    return $_SESSION[ 'company' ][ 'company_name' ];
  }
  public static function printCompanyName() {
    echo( self::getCompanyName() );
  }
  public static function printAccessName() {
    echo( $_SESSION[ 'user' ][ 'access_name' ] );
  }

  public static function getCountryFlagImgById( $countryId ) {
    global $sableDB;
    $countryNiceName = $sableDB->getValue( 'select country_nicename from country where country_id = ' . $countryId );
    return self::getCountryFlagImgByName( $countryNiceName );
  }

  public static function getCountryFlagImgByName( $countryName, $size = 128 ) {
    $flagImage = empty( $countryName ) ?
      '<image src="" alt="" title="" id="countryFlag"/>' : '<img src="' . SableSystem::getSableImgPath( 'flags/' . $size . '/' . ucfirst( $countryName ) ) . '.png" alt="' . ucfirst( $countryName ) . '" title="' . ucfirst( $countryName ) . '"  id="countryFlag"/>';
    return $flagImage;
  }

  public static function printCountryFlagImgByName( $countryName, $size = 128 ) {
    echo( self::getCountryFlagImgByName( $countryName, $size ) );
  }

  public static function getFontAwesomeOptions( $search ) {
    global $sableDB;
    $sql = 'select distinct(fa_code), fa_name from fontawesome';
    if ( $search )$sql .= ' where fa_name like %' . $search . '%';
    $sql .= ' group by fa_code order by fa_name';
    $icons = $sableDB->getRows( $sql );
    $html = '';
    foreach ( $icons as $opt ) {
      /*
      $name = str_replace('_', ' ', $opt['fa_name']);
      $name = ucfirst($name);
      */
      $html .= '<option value="' . $opt[ 'fa_name' ] . '" class="fontAwesomeList">' . $opt[ 'fa_code' ] . '</option>';
    }
    echo( $html );
  }

  public static function getFontAwesomeIcons( $search ) {
    if ( $search ) {
      $nulist = array();
      foreach ( $iconsFA as $fa ) {
        if ( stripos( $fa, $search ) !== false )$nulist[] = $fa;
      }
      return $fa;
    } else return $iconsFA;
  }

  private static function parseRSS( $doc, $maxFeeds ) {
    $data = [];
    $tz = ' UTC'; //' GMC'
    $cnt = count( $doc->channel->item );
    $c = 0;
    for ( $i = 0; $i < $cnt; $i++ ) {
      if ( $maxFeeds && ( $c >= $maxFeeds ) ) break;
      $data[ $i ] = [];
      $data[ $i ][ 'link' ] = $doc->channel->item[ $i ]->link;
      $data[ $i ][ 'title' ] = $doc->channel->item[ $i ]->title;
      $data[ $i ][ 'description' ] = $doc->channel->item[ $i ]->description;
      $data[ $i ][ 'pubDate' ] = $doc->channel->item[ $i ]->pubDate; //Thu, 29 Mar 2012 00:00:00 GMT

      if ( empty( $data[ $i ][ 'pubDate' ] ) ) {
        $data[ $i ][ 'pubDate' ] = array();
        $data[ $i ][ 'pubDate' ][] = date( 'Y-m-d H:i:s' );

        $data[ $i ][ 'pubDate' ][][ 'year' ] = date( 'Y' );
        $data[ $i ][ 'pubDate' ][][ 'month' ] = date( 'm' );
        $data[ $i ][ 'pubDate' ][][ 'day' ] = date( 'd' );
      } else {
        $data[ $i ][ 'pubDate' ][ 'year' ] = date( 'Y', strtotime( $data[ $i ][ 'pubDate' ] ) . $tz );
        $data[ $i ][ 'pubDate' ][ 'month' ] = date( 'm', strtotime( $data[ $i ][ 'pubDate' ] ) . $tz );
        $data[ $i ][ 'pubDate' ][ 'day' ] = date( 'd', strtotime( $data[ $i ][ 'pubDate' ] ) . $tz );
      }
      $c++;
    }
    return $data;
  }

  public static function getRSSFeed( $xml, $maxFeeds = 0 ) {
    $ch = curl_init( $xml );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    curl_setopt( $ch, CURLOPT_HEADER, 0 );
    $content = curl_exec( $ch );
    curl_close( $ch );
    $doc = new SimpleXmlElement( $content, LIBXML_NOCDATA );
    if ( isset( $doc->channel ) ) {
      $data = [];
      $data[ 'title' ] = $doc->channel->title;
      $data[ 'link' ] = $doc->channel->link;
      $data[ 'description' ] = $doc->channel->description;
      $data[ 'image' ] = $doc->channel->image;
      $data[ 'items' ] = self::parseRSS( $doc, $maxFeeds );
    }
    return $data;
  }

  public static function getFilteredRSSFeed( $xml, $params ) {
    /**
    	$params['keywords'][0] 	= 'example1';
    	$params['keywords'][1] 	= 'example2';
    	$params['maxfeeds'] 	= 0; 
    	$params['maxYear'] 		= 0;
    	$params['maxMonth']		= 0;
    **/
    $data = self::getRSSFeed( $xml, $params[ 'maxFeeds' ] );
    $result = [];
    $cnt = 0;

    foreach ( $data[ 'items' ] as $item ) {
      $found = false;
      $consider = true;

      if ( $params[ 'maxYear' ] ) {
        $consider = $item[ 'pubDate' ][ 'year' ] >= $params[ 'maxYear' ];
        if ( $consider && $params[ 'maxMonth' ] ) {
          $consider = $item[ 'pubDate' ][ 'month' ] <= $params[ 'maxMonth' ];
        }
      }

      if ( $consider ) {
        foreach ( $params[ 'keywords' ] as $kw ) {
          $found = stripos( $item[ 'title' ], $kw );
          if ( !$found ) {
            $found = stripos( $item[ 'description' ], $kw );
          } else {
            //SableDebug::debugout('found "'.$kw.'" in "'.$item['title'].'"');
          }
          if ( $found ) {
            //SableDebug::debugout('found "'.$kw.'" in "'.$item['description'].'"');
            break;
          }
        }

        if ( $found ) {
          $result[] = $item;
          $cnt++;
        }
      }
    }

    if ( $cnt ) {
      unset( $data[ 'items' ] );
      $data[ 'items' ] = $result;
    }

    return $data;
  }

  public static function getShareThis( $title, $summary, $img ) {
    $stTitle = 'st_title="' . $title . '"';
    $stSummary = 'st_summary="' . $summary . '"';
    $stImg = 'st_image="' . $img . '"';
    $stURL = 'st_url="' . SableSystem::getCallPageLink( SABLE_URL_ROOT . $_SESSION[ 'caller' ][ 'args' ][ 0 ] . '+' . $_SESSION[ 'caller' ][ 'args' ][ 1 ] . '+' . rand() ) . '"';
    $tags = ' ' . $stTitle . ' ' . $stSummary . ' ' . $stImg . ' ' . $stURL;

    $html = '<span class="st_sharethis"' . $tags . '></span>
				 <span class="st_facebook" ' . $tags . '></span>
				 <span class="st_googleplus"' . $tags . '></span>
				 <span class="st_email"' . $tags . '></span>
				 <span class="st_twitter"' . $tags . '></span>
				 <span class="st_whatsapp"' . $tags . '></span>';

    return $html;
  }

  public static function getBlogData( $row ) {
    global $sableDB;

    $doSharing = $row[ 'blog_sharing' ];
    $doLikes = $row[ 'blog_liking' ];
    $doComments = $row[ 'blog_commenting' ];

    $lft = 'col-md-6';
    $mdl = 'col-md-4';
    $rgt = 'col-md-2';

    $likeCount = $doLikes ? $sableDB->getValue( 'select blog_like_count from blog__likes where blog_id = ' . $row[ 'blog_id' ] ) : 0;
    $commentCount = $doComments ?
      $sableDB->getValue( 'select count(*) from blog__thread where tc_parent_id = 0 and blog_id = ' . $row[ 'blog_id' ] ) : 0;

    $shareBy = '
		<!--// Blog Data -->
		<div class="row">
			<div class="' . $lft . ' text-left">
				<h5>By ' . SableDBFunctions::getUserDisplayNameFromUserCode( $row[ 'user_code' ] ) . ',  
				' . date( 'd F Y', strtotime( $row[ 'create_date' ] ) ) . '</h5>
			</div>';

    $shareIcons = '';

    if ( $doComments || $doLikes || $doSharing ) {
      if ( $doComments && $doLikes && $doSharing ) {
        $shareIcons = SableGeneralFunctions::getShareThis( $row[ 'blog_title' ], $txt, $row[ 'blog_image' ] );
        $mdl = $lft;
        $rgt = $lft;
        $shareBy .= '<div class="' . $mdl . ' text-center">' . $shareIcons . '</div>';
        $shareBy .= '
				<div class="' . $rgt . ' text-right">
					<a href="#frmBlogLike"><i class="fa fa-thumbs-o-up" aria-hidden="true"></i>&nbsp;' . $likeCount . '</a>&nbsp;|&nbsp;
					<a href="#frmBlogComment"><i class="fa fa-comments-o" aria-hidden="true"></i>&nbsp;' . $commentCount . '</a>
				</div>';
      } elseif ( $doComments && $doLikes && ( !$doSharing ) ) {
        $shareBy .= '
				<div class="' . $rgt . ' text-right">
					<a href="#frmBlogLike"><i class="fa fa-thumbs-o-up" aria-hidden="true"></i>&nbsp;' . $likeCount . '</a>&nbsp;|&nbsp;
					<a href="#frmBlogComment"><i class="fa fa-comments-o" aria-hidden="true"></i>&nbsp;' . $commentCount . '</a>
				</div>';
      }
      elseif ( $doLikes && $doSharing && ( !$doComments ) ) {
        $mdl = $lft;
        $rgt = $lft;
        $shareBy .= '<div class="' . $mdl . ' text-center">' . $shareIcons . '</div>';
        $shareBy .= '
				<div class="' . $rgt . ' text-right">
					<a href="#frmBlogLike"><i class="fa fa-thumbs-o-up" aria-hidden="true"></i>&nbsp;' . $likeCount . '</a>&nbsp;
				</div>';
      }
      elseif ( ( !$doComments ) && ( !$doLikes ) && $doSharing ) {
        $shareBy .= '<div class="' . $mdl . ' text-center">' . $shareIcons . '</div>';
        $shareBy .= '
				<div class="' . $rgt . ' text-right">
					<a href="#frmBlogComment"><i class="fa fa-comments-o" aria-hidden="true"></i>&nbsp;' . $commentCount . '</a>
				</div>';
      }
    }
    $shareBy .= '</div><!-- Blog Data //-->';
    return $shareBy;
  }

  public static function getSEOFriendlyURLName( $title, $ext = '.php' ) {
    if ( SABLE_SEO_ENABLED )
      return strtolower( trim( preg_replace( '/[^a-zA-Z0-9]+/', '-', $title ), '-' ) ) . $ext;
    else
      return $title . $ext;
  }

  public static function getPageTitle() {
    $title = strtolower( trim( preg_replace( '/[^a-zA-Z0-9]+/', ' ', $_SERVER[ 'REQUEST_URI' ] ), ' ' ) );
    return ucwords( $title );
  }

  public static function formatName( $name ) {
    $tmp = strtolower( addslashes( trim( $name ) ) );
    return ucwords( $tmp );
  }

  public static function formatTitle( $title ) {
    //this function is an alias for formName:
    return self::formatName( $title );
  }

  public static function formatEmail( $email ) {
    return strtolower( trim( $email ) );
  }

  public static function replaceLineFeeds( $text, $delim ) {
    //		$html = preg_replace("/\R", $delim, $text);
    $html = preg_replace( "/\r|\n/", $delim, $text );
    /**
		$html = empty($text)?'':$text;
		$e = strpos($text, PEP_EOL);
		SableDebug::debug($e);			
		$b = strpos($text, 'br>');
		SableDebug::debug($b);		
		$n = strpos($text, '\n');
		SableDebug::debug($n);
		$r = strpos($text, '\r');
		SableDebug::debug($r);
		$html = str_replace('\n\r', $delim, $html);
		$html = str_replace('\n', $delim, $html);
		$html = str_replace('\r', $delim, $html);
		//$html = str_replace(',', $delim, $html);
	**/
    //SableDebug::debug($html);
    return $html;
  }

  public static function getDaysBetween( $dateA, $dateB ) {
    return round( intval( ( strtotime( $dateA ) - strtotime( $dateB ) ) / ( 60 * 60 * 24 ) ) );
  }

  public static function getTimeBetween( $TimeFrom, $TimeTo ) {
    $time1 = new DateTime( $TimeTo );
    $h1 = intval( $time1->format( 'H' ) );

    $time2 = new DateTime( $TimeFrom );
    $h2 = intval( $time2->format( 'H' ) );

    if ( $h2 > $h1 ) {
      $numdays = intval( ( $h2 - $h1 ) / 24 );
      $time2->add( new DateInterval( 'P' . $numdays . 'D' ) ); //add the number of days to the time value.
    }

    $timediff = $time1->diff( $time2 );
    $out = $timediff->format( '%y year %m month %d days %h hour %i minute %s second' );
    //		SableDebug::debug($out);
    return $out;
  }

  public static function getAgeFromDate( $date ) {
    $from = new DateTime( $date );
    $to = new DateTime( 'today' );
    return $from->diff( $to )->y;
  }

  public static function getInternationalNumber( $number, $countryCode = '27' ) {
    $pre = "+" . $countryCode;
    $chk = "";
    for ( $i = 0; $i < strlen( $countryCode ) + 1; $i++ )$chk .= $number[ $i ];
    if ( $chk !== $pre ) {
      $temp = self::replaceWhitespace( $number ); //take out all spaces, etc.
      $temp = str_replace( "(", "", $temp );
      $temp = str_replace( ")", "", $temp );
      $temp = str_replace( "-", "", $temp );
      $temp = str_replace( "[", "", $temp );
      $temp = str_replace( "]", "", $temp );
      $temp = str_replace( ",", "", $temp );
      $temp = str_replace( ".", "", $temp );
      $temp = ltrim( $temp, '0' ); //remove leading zeros
      $temp = "+" . $countryCode . $temp;
      $res = $temp;
    } else $res = $number; //already in the correct format
    return $res;
  }

  public static function getDisplayPhoneNo( $num ) {
    $num = trim( $num );
    $num = str_replace( ' ', '', $num );
    $num = str_replace( '_', '', $num );
    $num = str_replace( '-', '', $num );
    $num = str_replace( '.', '', $num );
    return $num[ 0 ] . $num[ 1 ] . $num[ 2 ] . ' ' . $num[ 3 ] . $num[ 4 ] . $num[ 5 ] . ' ' . $num[ 6 ] . $num[ 7 ] . $num[ 8 ] . $num[ 9 ];
  }

  public static function getPhoneNoLink( $num ) {
    return '+27' . $num[ 1 ] . $num[ 2 ] . '-' . $num[ 3 ] . $num[ 4 ] . $num[ 5 ] . '-' . $num[ 6 ] . $num[ 7 ] . $num[ 8 ] . $num[ 9 ];
  }

  public static function getNumericPhoneNo( $num ) {
    $tmp = self::removeSpaces( $num );
    if ( strlen( $tmp ) == 9 ) {
      if ( intval( $tmp[ 0 ] ) !== 0 )$tmp = '0' . $tmp;
    }
    return $tmp;
  }

  public static function fixNames( $name, $dummy = "" ) {
    $delim = strpos( $name, '-' ) ? '-' : ' ';
    $names = explode( $delim, $name );
    $ret = '';
    $c = 0;
    foreach ( $names as $n ) {
      $tmp = strtolower( $n );
      $tmp = ucfirst( $tmp );
      $nm = $c ? $delim . $tmp : $tmp;
      $ret .= $nm;
      $c++;
    }
    return $ret;
  }

  public static function getAddressLines( $address, $minLines = 2, $maxLines = 99 ) {
    $tmp = $address;
    $tmp = str_replace( ',', '|', $tmp );
    //$tmp = str_replace(' ', '|', $tmp);
    $ret = explode( '|', $tmp );
    $cnt = sizeof( $ret );
    if ( $cnt < $minLines ) {
      $bal = $minLines - $cnt;
      for ( $i = 0; $i < $bal; $i++ )$ret[] = '';
    }
    return $ret;
  }

  public static function printProtectedEmailAddress( $emailAddress, $href = true ) {
    $email = explode( '@', $emailAddress );
    $js = '<script>';
    $js .= 'var em = ("' . $email[ 0 ] . '" + "@" + "' . $email[ 1 ] . '"); ';
    if ( $href ) {
      $js .= 'document.write(\'<a href="mailto:\'+em+\'">\'+em+\'</a>\')';
    } else {
      $js .= 'document.write(em)';
    }
    $js .= '</script>';
    echo( $js );
  }

  public static function getDistanceBetweenLocations( $lat1, $lon1, $lat2, $lon2, $unit = "K" ) {
    /*
    $lat1 = floatval($lat1); 
    $lon1 = floatval($lon1); 
    $lat2 = floatval($lat2); 
    $lon2 = floatval($lon2); 
    */

    if ( ( $lat1 == $lat2 ) && ( $lon1 == $lon2 ) ) {
      return 0;
    } else {
      $theta = $lon1 - $lon2;
      $dist = sin( deg2rad( $lat1 ) ) * sin( deg2rad( $lat2 ) ) + cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) * cos( deg2rad( $theta ) );
      $dist = acos( $dist );
      $dist = rad2deg( $dist );
      $miles = $dist * 60 * 1.1515;
      $unit = strtoupper( $unit );

      if ( $unit == "K" ) {
        return ( $miles * 1.609344 );
      } else {
        if ( $unit == "N" ) {
          return ( $miles * 0.8684 );
        } else {
          return $miles;
        }
      }
    }
  }

  public static function specialCharsToHTMLEncode( $text ) {
    //https://ascii.cl/htmlcodes.htm
    $sub = str_replace( '&#233;', 'é', $text );
    $sub = str_replace( '&#224;', 'à', $sub );
    $sub = str_replace( '&#225;', 'á', $sub );
    $sub = str_replace( '&#226;', 'â', $sub );
    $sub = str_replace( '&#227;', 'ã', $sub );
    $sub = str_replace( '&#228;', 'ä', $sub );
    $sub = str_replace( '&#229;', 'å', $sub );
    $sub = str_replace( '&#230;', 'æ', $sub );
    $sub = str_replace( '&#231;', 'ç', $sub );
    $sub = str_replace( '&#232;', 'è', $sub );
    $sub = str_replace( '&#234;', 'ê', $sub );
    $sub = str_replace( '&#235;', 'ë', $sub );
    $sub = str_replace( '&#252;', 'ü', $sub );
    $sub = str_replace( '&#251;', 'û', $sub );
    $sub = str_replace( '&#250;', 'ú', $sub );
    $sub = str_replace( '&#249;', 'ù', $sub );
    $sub = str_replace( '&#246;', 'ö', $sub );
    $sub = str_replace( '&#245;', 'õ', $sub );
    $sub = str_replace( '&#244;', 'ô', $sub );
    $sub = str_replace( '&#243;', 'ó', $sub );
    $sub = str_replace( '&#242;', 'ò', $sub );
    $sub = str_replace( '&#241;', 'ñ', $sub );
    $sub = str_replace( '&#240;', 'ð', $sub );
    $sub = str_replace( '&#239;', 'ï', $sub );
    $sub = str_replace( '&#238;', 'î', $sub );
    $sub = str_replace( '&#237;', 'í', $sub );
    $sub = str_replace( '&#236;', 'ì', $sub );
    //$sub = str_replace('xxx', 'zzz', $sub);

    return $sub;
  }

  private static function splitAddressLines( $addresseId, $coords = null ) {
    global $sableDB;

    $res = 0;
    $itms = explode( '|', $addresseId );
    $c = 0;
    $row = [];
    $lng = 0;
    $lat = 0;
    $sql = '';
    $arow = '';
    $multi = strpos( $addresseId, '|' );

    $lat = ( $coords[ 'address_lat' ] ?? 0 ) ? $coords[ 'address_lat' ] : 0;
    $lng = ( $coords[ 'address_lng' ] ?? 0 ) ? $coords[ 'address_lng' ] : 0;

    if ( $multi ) {
      foreach ( $itms as $itm ) {
        $d = $c ? '|' : '';
        $c++;

        if ( is_array( $coords ) ) {
          $row[ 'address_lng' ] = $lng;
          $row[ 'address_lat' ] = $lat;
        } else {
          $sql = 'select address_lat, address_lng from address where address_id = ';
          $row = $sableDB->getRow( $sql . $itm );
        }
        $res .= $d . $row[ 'address_lng' ] . ',' . $row[ 'address_lat' ];
      }
    } else {
      $sql = 'select address_lat, address_lng from address where address_id = ';

      if ( $lng ) {
        $res = $lng . ',' . $lat;
      } else {
        $arow = $sableDB->getRow( $sql . $addresseId );
        $res = $arow[ 'address_lng' ] . ',' . $arow[ 'address_lat' ]; //no spaces!
      }
    }

    return $res;
  }

  public static function getDistanceMatrix( $origAddressId, $destAddressId, $coords = null ) {
    global $sableDB;
    $orig = null;
    $dest = null;
    $matrix = 0;

    $matrix = SableDBFunctions::getDistanceMatrixBetweenAddresses( $origAddressId, $destAddressId );

    if ( !$matrix ) {
      $orig = self::splitAddressLines( $origAddressId, ( $coords[ 'orig' ] ?? null ) );
      $dest = self::splitAddressLines( $destAddressId, ( $coords[ 'dest' ] ?? null ) );

      $url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=" . $orig . "&destinations=" . $dest . "&key=" . GOOGLE_API_WEB_SERVER_KEY;

      $ch = curl_init();
      curl_setopt( $ch, CURLOPT_URL, $url );
      curl_setopt( $ch, CURLOPT_POST, 0 );
      curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
      curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
      curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );

      $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); // this results 0 every time
      $response = curl_exec( $ch );
      $data = json_decode( $response, true );

      $matrix = [];
      $matrix[ 'distance' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'distance' ][ 'value' ] ?? 0; //value in meters 7771 = 7.8km's!
      $matrix[ 'duration' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'duration' ][ 'value' ] ?? 0; //value in seconds 722 = 12 minutes
      $matrix[ 'distance_text' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'distance' ][ 'text' ] ?? '';
      $matrix[ 'duration_text' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'duration' ][ 'text' ] ?? '';

      SableDBFunctions::storeDistanceMatrix( $origAddressId, $destAddressId,
        $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'distance' ],
        $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'duration' ] );
    }

    return $matrix;
  }

  public static function getDistanceMatrix_( $origAddressId, $destAddressId, $coords = null ) {
    /*
    This function shows the distance between a origin(s) and destination(s). It will also give us the travel time for driving.
    Parameters should come in the format array[0 => "lat,long", 1 => "lat,long"].
    */
    //$origAddressId, $destAddressId
    global $sableDB;
    $orig = null;
    $dest = null;
    $matrix = 0;

    if ( strpos( $origAddressId, '|' ) ) {
      $ors = explode( '|', $origAddressId );
      $c = 0;
      foreach ( $ors as $or ) {
        $d = $c ? '|' : '';
        $c++;

        if ( is_array( $coords[ 'orig' ] ) ) {
          $orow[ 'address_lng' ] = $coords[ 'orig' ][ 'address_lng' ];
          $orow[ 'address_lat' ] = $coords[ 'orig' ][ 'address_lat' ];
        } else {
          $sql = 'select address_lat, address_lng from address where address_id = ';
          $orow = $sableDB->getRow( $sql . $or );
        }
        $orig .= $d . $orow[ 'address_lng' ] . ',' . $orow[ 'address_lat' ];
      }

      if ( strpos( $destAddressId, '|' ) ) {
        $des = explode( '|', $destAddressId );
        $c = 0;
        foreach ( $des as $de ) {
          $d = $c ? '|' : '';
          $c++;

          if ( is_array( $coords[ 'dest' ] ) ) {
            $drow[ 'address_lng' ] = $coords[ 'dest' ][ 'address_lng' ];
            $drow[ 'address_lat' ] = $coords[ 'dest' ][ 'address_lat' ];
          } else {
            $sql = 'select address_lat, address_lng from address where address_id = ';
            $drow = $sableDB->getRow( $sql . $de );
          }
          $dest .= $d . $drow[ 'address_lng' ] . ',' . $drow[ 'address_lat' ];
        }
      }

    } else {
      $sql = 'select address_lat, address_lng from address where address_id = ';
      if ( isset( $coords[ 'orig' ][ 'address_lng' ] ) ) {
        $orig = $coords[ 'orig' ][ 'address_lng' ] . ',' . $coords[ 'orig' ][ 'address_lat' ];
      } else {
        $orow = $sableDB->getRow( $sql . $origAddressId );
        $orig = $orow[ 'address_lng' ] . ',' . $orow[ 'address_lat' ]; //no spaces!
      }

      if ( isset( $coords[ 'dest' ][ 'address_lng' ] ) ) {
        $ordestig = $coords[ 'dest' ][ 'address_lng' ] . ',' . $coords[ 'dest' ][ 'address_lat' ];
      } else {
        $drow = $sableDB->getRow( $sql . $destAddressId );
        $dest = $drow[ 'address_lng' ] . ',' . $drow[ 'address_lat' ]; //no spaces!
      }
    }

    /**
    $origins		= array(0 => $orow['address_lng'].','.$orow['address_lat']);
    $destinations	= array(0 => $drow['address_lng'].','.$drow['address_lat']);
		
    $orig = self::removeSpaces($origins);
    $dest = self::removeSpaces($destinations);
    $orig = implode('|', $orig); //e.g. lat,lng|lat,lng
    $dest = implode('|', $dest);
    **/

    /**
    Before calling on the distance matrix (which can cost money) we first check if the distance between the two addresses haven't already been stored. If they are stored, then us that value.
    If it doesn't exist, then save it.
    **/

    $matrix = SableDBFunctions::getDistanceMatrixBetweenAddresses( $origAddressId, $destAddressId );
    if ( !$matrix ) {
      $url = "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=" . $orig . "&destinations=" . $dest . "&key=" . GOOGLE_API_WEB_SERVER_KEY;

      $ch = curl_init();
      curl_setopt( $ch, CURLOPT_URL, $url );
      curl_setopt( $ch, CURLOPT_POST, 0 );
      curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
      curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
      curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );

      $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); // this results 0 every time
      $response = curl_exec( $ch );
      $data = json_decode( $response, true );

      $matrix = [];
      $matrix[ 'distance' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'distance' ][ 'value' ] ?? 0; //value in meters 7771 = 7.8km's!
      $matrix[ 'duration' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'duration' ][ 'value' ] ?? 0; //value in seconds 722 = 12 minutes
      $matrix[ 'distance_text' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'distance' ][ 'text' ] ?? '';
      $matrix[ 'duration_text' ] = $data[ 'rows' ][ 0 ][ 'elements' ][ 0 ][ 'duration' ][ 'text' ] ?? '';

      SableDBFunctions::storeDistanceMatrix( $origAddressId, $destAddressId, $matrix[ 'distance' ], $matrix[ 'duration' ] );
    }

    return $matrix;
  }
}

