<?php
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

 
class PortaneoDbFetcher {
  private $db;
  private $url_prefix;

  // private $cache;
  
  // Singleton
  private static $fetcher;

  private function __construct() {// Not currently used
        //$this->cache = Cache::createCache(Config::get('data_cache'), 'PartuzaDbFetcher');
        
  }
  
  static function get() {
    // This object is a singleton
    if (! isset(PortaneoDbFetcher::$fetcher)) {
      PortaneoDbFetcher::$fetcher = new PortaneoDbFetcher();
    }
    return PortaneoDbFetcher::$fetcher;
  }

  private function connectDb() {
    global $shindigConfig;
    $path = $shindigConfig['plugin_base_paths'];
    $configFile = $path . "\config.php";
    if (file_exists($configFile)) {
        include $configFile;
    }
    else {
        $configFile = $path . "/config.php";
        if (file_exists($configFile)) {
            include $configFile;
        }
    }
    if (! isset($config)) {
        error_log("Could not locate portaneo's configuration file while scanning extension_class_paths");
      throw new Exception("Could not locate portaneo's configuration file while scanning extension_class_paths ({$extension_class_paths})");
    }
    
    $this->db = mysqli_connect($config['db_host'], $config['db_user'], $config['db_passwd'], $config['db_database']);
    mysqli_select_db($this->db, $config['db_database']);
    $this->url_prefix = $config['portaneo_url'];
    if (substr($this->url_prefix, strlen($this->url_prefix) - 1, 1) == '/') {
      // prevent double //'s in the profile and thumbnail urls by forcing the prefix to end without a tailing /
      $this->url_prefix = substr($this->url_prefix, 0, strlen($this->url_prefix) - 1);
    }
  }
  
  private function checkDb() {
    if (! is_object($this->db)) {
      $this->connectDb();
    }
  }   
   

  public function getFriendIds($person_id) {
    $this->checkDb();
    $ret = array();
    $person_id = intval($person_id);
    $res = mysqli_query($this->db, "select user_id, friend_id from network where user_id = $person_id or friend_id = $person_id");
    while (list($pid, $fid) = @mysqli_fetch_row($res)) {
      $id = ($pid == $person_id) ? $fid : $pid;
      $ret[] = $id;
    }
    return $ret;
  }   
   
  
   
  public function getPeople($ids, $fields, $options, $token) {
    $first = $options->getStartIndex();
    $max = $options->getCount();
    $this->checkDb();
    $ret = array();
    $filterQuery = '';
    
    if ($options->getFilterBy() == 'hasApp') {
      // remove the filterBy field, it's taken care of in the query already, otherwise filterResults will disqualify all results
      $options->setFilterBy(null);
      $appId = $token->getAppId();
      $filterQuery = ""; // and id in (select person_id from person_applications where application_id = $appId)";
    } elseif ($options->getFilterBy() == 'all') {
      $options->setFilterBy(null);
    } elseif ($options->getFilterBy() == '@friends') {
      $options->setFilterBy(null);
      $somePersonId = $options->getFilterValue();
      if ($options->getFilterValue() == '@viewer') {
        $somePersonId = $token->getViewerId();
      } elseif ($options->getFilterValue() == '@owner') {
        $somePersonId = $token->getOwnerId();
      }
      $filteredIds = array();
      foreach ($ids as $personId) {
        if (in_array($somePersonId, $this->getFriendIds($personId))) {
          $filteredIds[] = $personId;
        }
      }
      $ids = $filteredIds;
    }

    $query = "select * from users where id in (" . implode(',', $ids) . ") $filterQuery order by id ";
    $res = mysqli_query($this->db, $query);
    if ($res) {
      while ($row = @mysqli_fetch_array($res, MYSQLI_ASSOC)) {
        $person_id = $row['id'];
        $name = $this->convertName($row);
        $person = new Person($row['id'], $name);
        $person->setDisplayName($name->getFormatted());
        $person->setAboutMe($row['description']);
        $person->setStatus($row['activity']);
        $person->setThumbnailUrl(! empty($row['picture']) ? $this->url_prefix . $row['picture'] : '');
        if (! empty($row['picture'])) {
          // also report thumbnail_url in standard photos field (this is the only photo supported by partuza)
          //$person->setPhotos(array(
              //new Photo($this->url_prefix . $row['thumbnail_url'], 'thumbnail', true)));
        }
        $ret[$person_id] = $person;
      }
    }
    try {
      $ret = $this->filterResults($ret, $options);
      $ret['totalSize'] = count($ret);
    } catch (Exception $e) {
      $ret['totalSize'] = count($ret) - 1;
      $ret['filtered'] = 'false';
    }
    if ($first !== false && $max !== false && is_numeric($first) && is_numeric($max) && $first >= 0 && $max > 0) {
      $count = 0;
      $result = array();
      foreach ($ret as $id => $person) {
        if ($id == 'totalSize' || $id == 'filtered') {
          $result[$id] = $person;
          continue;
        }
        if ($count >= $first && $count < $first + $max) {
          $result[$id] = $person;
        }
        ++ $count;
      }
      return $result;
    } else {
      return $ret;
    }
  }   
  
  private function convertName($row) {
    $name = new Name($row['long_name']);
    $name->setGivenName($row['long_name']);
    $name->setFamilyName($row['long_name']);
    return $name;
  }     
  
  private function filterResults($peopleById, $options) {
    if (! $options->getFilterBy()) {
      return $peopleById; // no filtering specified
    }
    $filterBy = $options->getFilterBy();
    $op = $options->getFilterOperation();
    if (! $op) {
      $op = CollectionOptions::FILTER_OP_EQUALS; // use this container-specific default
    }
    $value = $options->getFilterValue();
    $filteredResults = array();
    $numFilteredResults = 0;
    foreach ($peopleById as $id => $person) {
      if ($person instanceof Person) {
        if ($this->passesFilter($person, $filterBy, $op, $value)) {
          $filteredResults[$id] = $person;
          $numFilteredResults ++;
        }
      } else {
        $filteredResults[$id] = $person; // copy extra metadata verbatim
      }
    }
    if (! isset($filteredResults['totalSize'])) {
      $filteredResults['totalSize'] = $numFilteredResults;
    }
    return $filteredResults;
  } 

  private function passesFilter($person, $filterBy, $op, $value) {
    $fieldValue = $person->getFieldByName($filterBy);
    if ($fieldValue instanceof ComplexField) {
      $fieldValue = $fieldValue->getPrimarySubValue();
    }
    if (! $fieldValue || (is_array($fieldValue) && ! count($fieldValue))) {
      return false; // person is missing the field being filtered for
    }
    if ($op == CollectionOptions::FILTER_OP_PRESENT) {
      return true; // person has a non-empty value for the requested field
    }
    if (! $value) {
      return false; // can't do an equals/startswith/contains filter on an empty filter value
    }
    // grab string value for comparison
    if (is_array($fieldValue)) {
      // plural fields match if any instance of that field matches
      foreach ($fieldValue as $field) {
        if ($field instanceof ComplexField) {
          $field = $field->getPrimarySubValue();
        }
        if ($this->passesStringFilter($field, $op, $value)) {
          return true;
        }
      }
    } else {
      return $this->passesStringFilter($fieldValue, $op, $value);
    }

    return false;
  }
  
  
  private function passesStringFilter($fieldValue, $op, $filterValue) {
    switch ($op) {
      case CollectionOptions::FILTER_OP_EQUALS:
        return $fieldValue == $filterValue;
      case CollectionOptions::FILTER_OP_CONTAINS:
        return stripos($fieldValue, $filterValue) !== false;
      case CollectionOptions::FILTER_OP_STARTSWITH:
        return stripos($fieldValue, $filterValue) === 0;
      default:
        throw new Exception('unrecognized filterOp');
    }
  }  
  
  
  public function createActivity($person_id, $activity, $app_id = '0') {
    $this->checkDb();
    $app_id = intval($app_id);
    $person_id = intval($person_id);
    $title = trim(isset($activity['title']) ? $activity['title'] : '');
    if (empty($title)) {
      throw new Exception("Invalid activity: empty title");
    }
    $body = isset($activity['body']) ? $activity['body'] : '';
    $title = mysqli_real_escape_string($this->db, $title);
    $body = mysqli_real_escape_string($this->db, $body);

    mysqli_query($this->db, "UPDATE users SET stat='$title', statdate=CURRENT_DATE WHERE id=$person_id");
    mysqli_query($this->db, "INSERT INTO  network_news ( user_id, pubdate, type, title, link, status ) VALUES   ($person_id, NOW(), 6, '$title', '', 3) ");
    if (! ($activityId = mysqli_insert_id($this->db))) {
      return false;
    }
    /*
    if (count($mediaItems)) {
      foreach ($mediaItems as $mediaItem) {
        // Updates the activityId of the media item if the activity is bound with the existing media item.
        if (isset($mediaItem['id']) && isset($mediaItem['albumId'])) {
          $mediaItemId = intval($mediaItem['id']);
          $albumId = intval($mediaItem['albumId']);
          $query = "update media_items set activity_id = $activityId where id = $mediaItemId and album_id = $albumId and owner_id = $person_id";
          $res = mysqli_query($this->db, $query);
          if ($res && @mysqli_affected_rows($this->db) == 1) {
            continue;
          }
        }
        $mediaItem['albumId'] = 0;
        $this->createMediaItemInternal($person_id, $app_id, $mediaItem, $activityId);
      }
    }
    */
    return true;
  }  
  
  
 
  public function getActivities($ids, $appId, $sortBy, $filterBy, $filterOp, $filterValue, $startIndex, $count, $fields, $activityIds) {
    //TODO add support for filterBy, filterOp and filterValue
    $this->checkDb();
    $activities = array();
    $ids = array_map('intval', $ids);
    $ids = implode(',', $ids);
    if (isset($activityIds) && is_array($activityIds)) {
      $activityIds = array_map('intval', $activityIds);
      $activityIdQuery = " and id in (" . implode(',', $activityIds);
    } else {
      $activityIdQuery = '';
    }
    //$appIdQuery = $appId ? " and app_id = " . intval($appId) : '';

    // return a proper totalResults count
    //$res = mysqli_query($this->db, "select count(id) from network_news where user_id in ($ids) $activityIdQuery $appIdQuery");
    $res = mysqli_query($this->db, "select count(id) from network_news where type=6 AND user_id in ($ids) $activityIdQuery");
    if ($res !== false) {
      list($totalResults) = mysqli_fetch_row($res);
    } else {
      $totalResults = '0';
    }
    $startIndex = (! is_null($startIndex) && $startIndex !== false && is_numeric($startIndex)) ? intval($startIndex) : '0';
    $count = (! is_null($count) && $count !== false && is_numeric($count)) ? intval($count) : '20';
    $activities['totalResults'] = $totalResults;
    $activities['startIndex'] = $startIndex;
    $activities['count'] = $count;
    $query = "
      select
        network_news.user_id as person_id,
        network_news.id as activity_id,
        network_news.title as activity_title,
        network_news.pubdate as created
      from
        network_news
      where
        network_news.type=6
      and  
        network_news.user_id in ($ids)
        $activityIdQuery
      order by
        created desc
      limit
        $startIndex, $count
      ";
    $res = mysqli_query($this->db, $query);
    if ($res) {
      if (@mysqli_num_rows($res)) {
        while ($row = @mysqli_fetch_array($res, MYSQLI_ASSOC)) {
          $activity = new Activity($row['activity_id'], $row['person_id']);
          $activity->setStreamTitle('activities');
          $activity->setTitle($row['activity_title']);
          //$activity->setBody($row['activity_body']);
          $activity->setUserId($row['person_id']);
          $activity->setPostedTime($row['created']);
          $activity->setMediaItems($this->getMediaItemsByActivityId($row['activity_id']));
          $activities[] = $activity;
        }
      } elseif (isset($activityIds) && is_array($activityIds)) {
        // specific activity id was specified, return a not found flag
        return false;
      }
      return $activities;
    } else {
      return false;
    }
  }

    private function getMediaItemsByActivityId($activity_id) {
        $mediaItems = array();
        $activity_id = intval($activity_id);
        /*
        $res = mysqli_query($this->db, "select * from media_items where activity_id = $activity_id");
        if ($res && @mysqli_num_rows($res)) {
          while ($row = @mysqli_fetch_array($res, MYSQLI_ASSOC)) {
            $mediaItems[] = $this->convertMediaItem($row);
          }
        }
        */
        return $mediaItems;
    }

    
    
    

    public function setAppData($person_id, $key, $value, $app_id) {
        $this->checkDb();
        $person_id = intval($person_id);
        $key = mysqli_real_escape_string($this->db, $key);
        $value = mysqli_real_escape_string($this->db, $value);
        $app_id = intval($app_id);

        if (empty($value)) {
          // empty key kind of became to mean "delete data" (was an old orkut hack that became part of the spec spec)
          if (! @mysqli_query($this->db, "delete from application_settings where application_id = $app_id and person_id = $person_id and name = '$key'")) {
            return false;
          }
        } else {
          if (! @mysqli_query($this->db, "insert into application_settings (application_id, person_id, name, value) values ($app_id, $person_id, '$key', '$value') on duplicate key update value = '$value'")) {
            return false;
          }
        }
        return true;
   }
    
    
    
    
    
    
    
    
    
    
    
 
  
  public function createMediaItemInternal($userId, $appId, $mediaItem, $activityId) {
    /*
    $this->checkDb();
    $userId = intval($userId);
    $appId = intval($appId);
    $activityId = $this->getEscapedValue($activityId);
    $created = time();
    $lastUpdated = $created;
    $startTime = $this->getEscapedField($mediaItem, 'startTime');
    $title = $this->getEscapedField($mediaItem, 'title');
    $description = $this->getEscapedField($mediaItem, 'description');
    $thumbnailUrl = $this->getEscapedField($mediaItem, 'thumbnailUrl');
    $language = $this->getEscapedField($mediaItem, 'language');
    $albumId = $this->getEscapedField($mediaItem, 'albumId');
    $fileSize = $this->getEscapedField($mediaItem, 'fileSize');
    $duration = $this->getEscapedField($mediaItem, 'duration');
    $numComments = $this->getEscapedField($mediaItem, 'numComments');
    $numViews = $this->getEscapedField($mediaItem, 'numViews');
    $numVotes = $this->getEscapedField($mediaItem, 'numVotes');
    $rating = $this->getEscapedField($mediaItem, 'rating');
    if (is_numeric($rating) && ($rating < 0 || $rating > 10)) {
      $rating = $this->getEscapedValue(null);
    }
    // Stores tagged_people and tags as json string.
    $taggedPeople = $this->getJsonEscapedField($mediaItem, 'taggedPeople');
    $tags = $this->getJsonEscapedField($mediaItem, 'tags');
    if (! isset($mediaItem['type']) || ! in_array(strtoupper($mediaItem['type']), MediaItem::$TYPES)) {
      throw new SocialSpiException("Type not correct.", ResponseError::$BAD_REQUEST);
    }
    $type = $this->getEscapedValue(strtoupper($mediaItem['type']));
    if (! isset($mediaItem['mimeType'])) {
      $mediaItem['mimeType'] = '';
    }
    $mimeType = $this->getEscapedField($mediaItem, 'mimeType');

    $url = $this->getEscapedField($mediaItem, 'url');

    $addressId = $this->getEscapedValue(null);
    if (isset($mediaItem['location'])) {
      $addressId = $this->createAddress($mediaItem['location']);
    }

    $query = "insert into media_items (album_id, mime_type, file_size, duration, created, " . "last_updated, language, address_id, num_comments, num_views, num_votes, rating, " . "start_time, title, description, tagged_people, tags, thumbnail_url, type, url, app_id, owner_id, activity_id) " . "values ($albumId, $mimeType, $fileSize, $duration, $created, $lastUpdated, $language, " . "$addressId, $numComments, $numViews, $numVotes, $rating, $startTime, $title, " . "$description, $taggedPeople, $tags, $thumbnailUrl, $type, $url, $appId, $userId, $activityId)";
    mysqli_query($this->db, $query);
    if (! ($mediaItemId = mysqli_insert_id($this->db))) {
      throw new SocialSpiException("Insert media item failed.", ResponseError::$INTERNAL_ERROR);
    } else {
      if ($addressId) {
        // Best effort to update the media_item_id field used for deletion.
        $query = "update addresses set media_item_id = $mediaItemId where id = $addressId";
        mysqli_query($this->db, $query);
      }
      $mediaItem['id'] = $mediaItemId;
      return $mediaItem;
    }
    */
  } 
  
  
  
}