<?php
/* ONCE upon a time, there was a token...
Once, there was a control, about a token, assigned to every instance of a game, meant to avoid user to play with themselves.
Now this control is fully functional in ehs, and we removed the token management for it created several problems in the join phase.
For example, if the user tried to join twice, he was warned and kicked off by the system, but it was still calculated as player by ehs,
that, in this case, would allow to join to a game needing two player even if you were one. Futhermore, if you tried to join a one game player
launching several games in the same time with the same user, a lot of instance were created and dismissed (but not killed) with no precise purpose, damaging the functionality of the monitors we've been creating for researcher debug purposes. 
*/

define('ETS_LOC_UNUSED',  '0');
define('ETS_LOC_PROFILE', '1');
define('ETS_LOC_GPS',     '2');
define('ETS_LOC_UNKNOWN', '3');

function ets_page_experiment_scores($node) {

  // Get the best three places
  $result = db_query("SELECT score, uid, created 
                        FROM {ets_experiment_scores} 
                       WHERE nid=:nid 
                         AND uid > 0
                       ORDER BY score DESC 
                       LIMIT 3", array(':nid' => $node->nid)
                    );

  $headers = array(
    t("#"),
    t("Name"),
    t("Score"),
    t("Date"),
  );

  $rows = array();
  $i=1;
  while ($row = $result->fetchObject()) {

    $account = user_load($row->uid);

    $tmp = ets_get_user_field($account, 'fullname');

    $fullname = $tmp ? $tmp[0] : $account->name;

    $rows[] = array('data' => array(
      $i++,
      $fullname,      
      round($row->score, 2),      
      format_date($row->created)
      ), 'no_striping' => true
    );
  }

  $out_best = array(
    '#type' => 'markup',
    '#markup' => theme('table', array('header' => $headers, 'rows' => $rows))
  );

  // Get the best three players (max)
  $result = db_query("SELECT uid, SUM(score) AS score_max
                        FROM {ets_experiment_scores}
                       WHERE nid=:nid 
                         AND uid > 0
                    GROUP BY uid
                    ORDER BY score_max DESC
                       LIMIT 3", array(':nid' => $node->nid)
                    );     

  $headers = array(
    t("#"),
    t("Name"),
    t("Score"),
  );

  $rows = array();
  $i=1;
  while ($row = $result->fetchObject()) {
    $account = user_load($row->uid);

    $tmp = ets_get_user_field($account, 'fullname');

    $fullname = $tmp ? $tmp[0] : $account->name;

    $rows[] = array('data' => array(
      $i++,
      $fullname,      
      round($row->score_max, 2))
      , 'no_striping' => true  
    );
  }

  $out_max = array(
    '#type' => 'markup',
    '#markup' => theme('table', array('header' => $headers, 'rows' => $rows))
  );

  // Get the best three players (average)
  $result = db_query("SELECT uid, AVG(score) AS score_avg
                        FROM {ets_experiment_scores}
                       WHERE nid=:nid 
                         AND uid > 0
                    GROUP BY uid
                    ORDER BY score_avg DESC
                       LIMIT 3", array(':nid' => $node->nid)
                    );     

  $headers = array(
    t("#"),
    t("Name"),
    t("Score"),
  );

  $rows = array();
  $i=1;
  while ($row = $result->fetchObject()) {

    $account = user_load($row->uid);

    $tmp = ets_get_user_field($account, 'fullname');

    $fullname = $tmp ? $tmp[0] : $account->name;

    $rows[] = array('data' => array(
      $i++,
      $fullname,      
      round($row->score_avg, 2),
      ), 'no_striping' => true   
    );
  }

  $out_avg = array(
    '#type' => 'markup',
    '#markup' => theme('table', array('header' => $headers, 'rows' => $rows))
  );

  global $user;

  if ($user->uid == 1) {
    $limit = 1000000;
  } else {
    $limit = 10;
  }

  // Get the latest three scores (average)
  $result = db_query("SELECT uid, score, created, instance_id
                        FROM {ets_experiment_scores}
                       WHERE nid=:nid 
                    ORDER BY created DESC
                       LIMIT $limit", array(':nid' => $node->nid)
                    );     

  $headers = array(
    t("#"),
    t("Name"),
    t("Score"),
    t("Date"),
    t("Instance"),
  );

  $rows = array();
  $i=1;
  while ($row = $result->fetchObject()) {

    if ($row->uid > 0) {
      $account = user_load($row->uid);
      $tmp = ets_get_user_field($account, 'fullname');
      $fullname = $tmp ? $tmp[0] : $account->name;
    } else {
      $fullname = "(Anonymous)";
    }

    $rows[] = array(
      $i++,
      $fullname,      
      round($row->score, 2),      
      format_date($row->created),
      preg_replace("/_.*/", "", $row->instance_id)
    );
  }

  $out_lst = array(
    '#type' => 'markup',
    '#markup' => theme('table', array('header' => $headers, 'rows' => $rows))
  );

  return array(
    'h_best' => array(
      '#type' => 'markup',
      '#markup' => '<h2>Best 3 scores</h2>'
    ),
    'out_best' => $out_best,
    'h_max' => array(
      '#type' => 'markup',
      '#markup' => '<h2>Max 3 scores (overall)</h2>'
    ),
    'out_max' => $out_max,
    'h_avg' => array(
      '#type' => 'markup',
      '#markup' => '<h2>Max 3 scores (average)</h2>'
    ),
    'out_avg' => $out_avg,
    'h_lst' => array(
      '#type' => 'markup',
      '#markup' => "<h2>Latest {$limit} scores</h2>"
    ),
    'out_lst' => $out_lst,
  );  

}

/* Display a page for the user, with his/her experiment statistics
 * (a table with the experiment name and started and ended instances
 */
function ets_page_user_statistics($account) {
  
  $headers = array(
    t("Experiment"),
    t("Started"),
    t("Ended"),
    t("Score (sum)"),
    t("Score (avg)"),
    t("Latest"),
    t("(more)"),
  );

  $result = db_query("SELECT n.title, s.*
                        FROM {ets_user_stats} s
                        JOIN {node} n ON n.nid = s.nid
                       WHERE s.uid = :uid", array(':uid' => $account->uid)
  );

  $rows = array();
  
  while ($row = $result->fetchObject()) {

    list($scoreSum, $scoreAvg) = ets_score_get($row->nid, $account->uid);

    $histUrl = l('History', "user/{$account->uid}/ets-stats-hist/{$row->nid}");

    $rows[] = array(
      $row->title,      
      $row->inst_started,      
      $row->inst_ended,
      $scoreSum,
      $scoreAvg,
      format_date($row->updated),
      $histUrl
    );
  }
  
  return theme('table', array(
    'header' => $headers,
    'rows'   => $rows
  ));  
}

function ets_page_user_statistics_history($account, $node) {

  drupal_set_title(t("Your history for") . ' ' .$node->title);

  $headers = array(
    t("Date"),
    t("Score"),
  );

  $result = db_query("SELECT s.*
                        FROM {ets_experiment_scores} s
                       WHERE s.uid = :uid
                         AND s.nid = :nid
                        ORDER BY created DESC", array(':nid' => $node->nid, ':uid' => $account->uid)
  );

  $rows = array();

  while ($row = $result->fetchObject()) {
    $rows[] = array(
      format_date($row->created, 'medium'),
      round($row->score, 2),
    );
  }

  return array(
    'table' => array(
      '#type' => 'markup',
      '#markup' => theme('table', array('header' => $headers, 'rows' => $rows))
    ),
    'back' => array(
      '#type' => 'markup',
      '#markup' => l(t("Back to your statistics"), "user/{$account->uid}/ets-stats")
    )
  );  

}

function ets_score_get($nid, $uid) {
  $result = db_query("SELECT SUM(score) as score_sum,
                             AVG(score) as score_avg
                        FROM {ets_experiment_scores} s
                       WHERE s.uid = :uid
                         AND s.nid = :nid", array(':nid' => $nid, ':uid' => $uid)
  );
  $row = $result->fetchObject();
  return array(round($row->score_sum, 2), round($row->score_avg, 2));
}

function ets_page_experiment_statistics($node) {

  $headers = array(
    t("Experiment"),
    t("Created"),
    t("Dropped"),
    t("Performed"),
    t("Ended"),
    t("Latest"),
  );

  $result = db_query("SELECT n.title, s.*
                        FROM {ets_experiment_stats} s
                        JOIN {node} n ON n.nid = s.nid
                       WHERE s.nid = :nid", array(':nid' => $node->nid)
  );

  $rows = array();
  
  while ($row = $result->fetchObject()) {
    $rows[] = array(
      $row->title,      
      $row->inst_created,
      $row->inst_dropped,
      $row->inst_performed,
      $row->inst_ended,
      format_date($row->updated),
    );
  }
  
  return theme('table', 
      array(
              'header' => $headers,
    'rows'   => $rows
  ));  
}

function ets_page_experiments_statistics() {
  global $user;
  
  $cond = '';
  if (!user_access("administer nodes")) {
    drupal_set_title("Statistics for your experiments");
    $cond = "AND uid='{$user->uid}'";
  }
  
  $result = db_query("SELECT n.title, egs.*
                        FROM {node} n
                        JOIN {ets_experiment_stats} egs ON egs.nid = n.nid
                        WHERE n.type = 'experiment'
                        {$cond}
                        ORDER BY nid DESC");
  
  $table = array();
  
  $table['header'] = array('', 'Created', 'Dropped', 'Performed', 'Ended');
  $table['rows'] = array();
  foreach ($result as $row) {
    $table['rows'][] = array(l($row->title, "node/{$row->nid}"),
                             $row->inst_created,
                             $row->inst_dropped,
                             $row->inst_performed,
                             $row->inst_ended);
  }
  
  return theme('table', $table);
}


function ets_position_form($form, &$form_state) {

  $nid = arg(2);
  
  drupal_add_js(drupal_get_path('module', 'ets') . '/ets-position.js');
  
  global $user;

  $lat = $lng = 0;
  $exp_node = node_load($nid);
  $loc = '';
  
  if ($user->uid > 0) {
    $loc = location_load_locations($user->uid, 'uid');
    
    if (!empty($loc)) {
      $lat = round($loc[0]['latitude'], 6);
      $lng = round($loc[0]['longitude'], 6);
      $loc = $loc[0]['street'] . ", " . $loc[0]['city'] . " ({$lat}, {$lng})";
      
      $force_town = ets_get_node_field($exp_node, 'geo_force_town');
      // @TODO check if the current position is within the city boundaries
      if ($force_town) {
      }
    
    } else {
      $loc = "Location informations are missing! <a href=\"/user/{$user->uid}/edit\">Edit your profile</a>";
    }
  }

  $options = array(
    ETS_LOC_PROFILE => t('Use the location in your profile') . "<br><span class='ets-location'>{$loc}</span>",
    ETS_LOC_GPS     => t("Use the position from your device's GPS") . "<br><div id='ets-upd-position'>Waiting for data...</div>",
    ETS_LOC_UNKNOWN => t('Rather not say'),
  );

  $def_loc_type = isset( $_SESSION['ets_loc_type'] ) ? $_SESSION['ets_loc_type'] : '1';

  if ($user->uid == 0) {
    unset($options[ETS_LOC_PROFILE]);
    if (ETS_LOC_PROFILE == $def_loc_type) {
      $def_loc_type = ETS_LOC_GPS;
    }
  }
  
  $form = array();
  
  $form['loc_type'] = array(
    '#type'          => 'radios',
    '#title'         => t('This experiment needs you to specify your location'),
    '#title_display' => "before",
    '#default_value' => $def_loc_type,
    '#description'   => t('Your browser should be asking you your current position.'),
    '#options'       => $options
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Continue'),
  );
  
  $form['cancel'] = array(
    '#markup' =>  l("Cancel", "ets/get-position", array('attributes' => array('class' => 'overlay-close')))
  );
  
  return $form;
  
}

function ets_position_form_validate($form, &$form_state) {

  $loc_type = $form_state['values']['loc_type'];

  // Check if we can calculate a random position
  if (ETS_LOC_UNKNOWN == $loc_type) {
    $nid = arg(2);
    $coords = ets_get_random_point($nid);
    if (empty($coords)) {
      form_set_error('loc_type', t("Sorry, an error occurred: please contact the experiment administrator."));
      watchdog('ets', "Misconfigured experiment geolocation parameters (nid {$nid})", array(), WATCHDOG_WARNING);
    }
  }

}

function ets_position_form_submit($form, &$form_state) {
  
  global $user;

  $nid = arg(2);
  $exp_node = node_load($nid);
  
  $loc_type = $form_state['values']['loc_type'];
  
  // Validation: degrade location type to ETS_LOC_UNKNOWN if the user has an empty profile location
  if (ETS_LOC_PROFILE == $loc_type) {
    $loc = location_load_locations($user->uid, 'uid');
    if (empty($loc)) {
      $loc_type = ETS_LOC_UNKNOWN;
    }
  }
  
  // If the position is UNKNOWN use the default town and randomize a position
  if (ETS_LOC_UNKNOWN == $loc_type) {
    $coords = ets_get_random_point($nid);
  }
  
  $_SESSION['ets_loc_type'] = $loc_type;
  
  drupal_goto("/ets/exp-join/" . arg(2));
}

// ------------- XTRIBE MONITORS

function ets_instances_monitor() {
  // This page has a php version in xtribeMonitor.php. In order to have real-time data, the page needs to be updated
  // every N seconds. To do this, without having to reload the whole page, i had to use an ajax call, located in 
  // xtribeMonitorFunctions.js. The ajax call loads in the main page div the php version of the page.

  // Setting the javascript that will update the page every N seconds in order to have real-time results
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/instancesMonitorFunctions.js");
  
  // ------ INSTANCES MONITOR
  drupal_set_title("Instances Monitor");

  $output="<div class='x_monitor'>";
  $output.= "<div class='x_monitor' style='font-size:11px !important; line-height: 13px;'>Instances Monitor shows the activity of all games' instances monitoring their current state. The states of istances, showed in table, usually occur in sequence. Only active instances are shown. An instance is considered 'active' if exists and is not ended/dropped and no user leaved during the game. The monitor update itself in real-time with a maximum delay of two seconds.<br>
  <strong style='color:#8AAF45;'>Legend:</strong><br>
  - # : id of the instance.<br>
  - User(s): Drupal User id of user(s) involved in the instance.<br>
  - Created: A user started the instance for the first time (In this case, 'User' contains Drupal User id and guid of the first user that joined).<br>
  - Started: The number of users needed is reached so the instance is started (In this case, 'User' contains Drupal User id and guid of each user that joined the instance)<br>
  - Performed: The manager sent a 'ready' message<br>
  - Ended: The manager sent an 'over' message, which means the instance is ended in the correct way.<br>
  - Dropped (eventually): The users all leaved before beginning the instance or something prevented the game to begin (the manager is not responding, for example).<br>
  - Error (eventually): An error occurred. For example, a user leaved during the game. (At the moment, this is considered closing the instance.)<br>
  - Hunged: A system error occured and the instances has been forcedly closed as the Xtribe restarted.
  </div><br>
  <div class='substitute'>";

  $headers = array(
    //array(t("Instance"), 'sort' => 'asc'),
    t("#"),
    t("User(s)"), 
    t("Created"),
    t("Started"),
    t("Performed"),
    t("Ended"),
    t("Dropped"),
    t("Error"),
    t("Hunged"),
  );

  global $user;
  $result = db_query("SELECT i.*, n.title
                        FROM {ets_instances} i, {node} n
			WHERE i.nid=n.nid
			AND i.inst_dropped IS NULL 
      AND i.inst_ended IS NULL
      AND i.inst_error IS NULL
      AND i.inst_hunged IS NULL
      ORDER By nid, instance_id ASC",  array(':uid' => $user->uid)
  );

  $rows = array();
  
  $nid=-1;
  while ($row = $result->fetchObject()) {
  	// convert timestamp in dates (if not empty)	
  	if($row->inst_created != ''){ $date_created=date('d/m/Y H:i',$row->inst_created);
  	}else{ $date_created=''; }
    if($row->inst_started != ''){ $date_started=date('d/m/Y H:i',$row->inst_started);
    }else{ $date_started=''; }
    if($row->inst_performed != ''){ $date_performed=date('d/m/Y H:i',$row->inst_performed); 
    }else{ $date_performed=''; }
    if($row->inst_ended != ''){ $date_ended=date('d/m/Y H:i',$row->inst_ended);
    }else{ $date_ended=''; }
  	if($row->inst_dropped != ''){ $date_dropped=date('d/m/Y H:i',$row->inst_dropped);
  	}else{ $date_dropped=''; }
    if($row->inst_error != ''){ $date_error=date('d/m/Y H:i',$row->inst_error);
    }else{ $date_error=''; }
    if($row->inst_hunged != ''){ $date_hunged=date('d/m/Y H:i',$row->inst_hunged);
    }else{ $date_hunged=''; }


  	if($row->nid != $nid && $nid!=-1){

  		$output .= '<a id="displayText" href="javascript:toggle('.$nid.');">Experiment: '.$title.' '.'</a><br><br>';
      //$output .= '<a id="displayText" href="javascript:toggle('.$nid.');">Experiment: '.$title.' '.'</a><br><br><div id="toggleText_'.$nid.'" style="display: visible">';
  		$output .=theme('table', array(
  		    'header' => $headers,
  		    'rows'   => $rows
  		  ));
  		$output .= theme('pager');	
  		//$output .= '</div>';
  		unset($rows);
	  }

  	$nid= $row->nid;
  	$title= $row->title;

  	//todo scelta guid id
  	$rows[] = array(
    	$row->instance_id,
    	($row->uid)/*."<br>".($row->guid)*/,      
    	$date_created,
      $date_started,
      $date_performed,
      $date_ended,
    	$date_dropped,
    	$date_error,
      $date_hunged   	
    );
  }

  if(!count($rows)==0){
  	$output .= '<a id="displayText" href="javascript:toggle('.$nid.');">Experiment: '.$title.' '.'</a><br><br>';
    //$output .= '<a id="displayText" href="javascript:toggle('.$nid.');">Experiment: '.$title.' '.'</a><br><br><div id="toggleText_'.$nid.'" style="display: visible">';
  	$output .=theme('table', array(
		    'header' => $headers,
		    'rows'   => $rows
		  ));
  	//$output .= '</div><br>';
  }else{
    $output .= 'No active instance available';
  }

  $output .= '</div>';
  $output .= '</div>';
  return $output;
}

function ets_managers_monitor() {
  // This page has a php version in xtribeMonitor.php. In order to have real-time data, the page needs to be updated
  // every N seconds. To do this, without having to reload the whole page, i had to use an ajax call, located in 
  // xtribeMonitorFunctions.js. The ajax call loads in the main page div the php version of the page.
  
  // Setting the javascript that will update the page every N seconds in order to have real-time results
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/managersMonitorFunctions.js");

  drupal_set_title("Managers Monitor");

  // ------ MANAGERS MONITOR
  $output="<div class='x_monitor'>";
  $output.= "<div style='float:left; font-size:11px !important; line-height: 13px;'>Managers Monitor shows the current status of all games' managers. <br>
  <strong style='color:#8AAF45;'>Legend:</strong><br>
  - Game: Extended name of the game.<br>
  - Manager Uri: The current address of the game's own manager.<br>
  - Status: The status of manager represented by a green light if the manager is up and running, and a red one if it is not available for any reason.<br>
  - Response: The response time of the manager, in milliseconds.<br><br>
  </div>
  <table border='1' width='430' style='font-size:11px !important;'>
  <tbody>
   <tr>
    <td rowspan='2' valign='middle' >
      The purpose of this monitor is monitoring not only the funcionality of managers, but their response during time. As you open the monitor you'll be presented with the current status and response time of managers. You can choose to update this data once, by clicking the 'Update Now' button, or to enable a real-time update modality, by checking (or unchecking) the 'Real-time' checkbox. When you enable it, the page will be automatically updated every now and then, in order to show you results during time. Please consider a little delay in update, due to time necessary to actually retrieve informations, increasing with the number of the managers that have to be checked.
    </td>
    <td width='13%''><input type='checkbox' id='realtime' value='0'style='float: left;>'>
                <div style='font-size:11px !important; margin-top:4px; margin-left:3px;'>Real-time</div></td>
   </tr>
   <tr>
    <td><a class='btn btn-success' id='updatenow' style='font-size:11px !important;'>Update now</a></td>
   </tr>
  </tbody>
  </table>
  <div class='substitute'>";

  $headers = array(
    t("Game"),
    t("Manager Uri"), 
    t("Status"),
    t("Response"),
  );

  global $user;  
  $user->uid ;

  $query_m="SELECT u.entity_id, u.field_mgr_uri_value, n.title
      FROM {field_data_field_mgr_uri} u, {node} n
      WHERE u.entity_id=n.nid";
  if (!in_array('Administrator', $user->roles)) {
    $query_m.=" AND n.uid =:uid";
  }
  $query_m.=" ORDER By n.title ASC";
      
  $result = db_query($query_m, array(':uid' => $user->uid));
  $rows = array();

  if ($result->rowCount()) {
    while ($row = $result->fetchObject()) {
      // Get host and port separated from complete uri
      $uriParsed=parse_url(trim($row->field_mgr_uri_value));
      $managerHost=$uriParsed['host'];
      $managerPort=$uriParsed['port'];

      // Test if manager is alive
      // ip,port,system level error number,error message string, timeout (seconds)
      // Pay attention to the timeout! To work without delay it must be equal to the interval
      // between an update of the page and the other (defined in xtribeMonitorFunctions.js)
      
      $time_start = getmicrotime();
      $valid = @fsockopen($managerHost, $managerPort, $errno, $errstr, 2); 
      $time_end = getmicrotime();
      $time_response = $time_end - $time_start;

      $url_img_onoff="http://".$_SERVER['SERVER_NAME'].'/sites/all/modules/ets/images/';
      $offline=$url_img_onoff.'offline.png';
      $online=$url_img_onoff.'online.png';
      if (!$valid) $status = '<img src="'.$offline.'" height="35" width="35">';
      else $status = '<img src="'.$online.'" height="35" width="35">';

      $rows[] = array(
        $row->title,
        $row->field_mgr_uri_value,      
        $status,
        substr($time_response , 0, 12)
      );
    }
    $output .=theme('table', array(
            'header' => $headers,
            'rows'   => $rows
          ));
    $output .= theme('pager');  
    unset($rows);
  }else{
    $output .= 'No result found';
  }

  $output .="</div>";
  $output .="</div>";
  return $output;
}

function getmicrotime(){
  list($usec,$sec) = explode(" ",microtime());
    $micro=((float)$usec +(float)$sec);
    return $micro;
}

// ------------- END XTRIBE MONITORS

// ------------- XTRIBE SHARED EXPERIMENTS
function ets_shared_experiments(){
  drupal_set_title("Shared Experiment");

  // ------ SHARED EXPERIMENT
  $output .= "<div style='font-size:13px !important; line-height: 18px;'>Your first time on Xtribe as developer and you don't really know how to start building your game? Or curious about other's work in developing their own games, using the platform? Please, take a look to the code other developers shared with us. <br><br><strong><em style='color:#8AAF45;'>'If i have seen further it is by standing on the shoulders of giants.' Isaac Newton </em></strong><br><br>
  </div>";

  $json = file_get_contents('http://bitbucket.org/!api/1.0/repositories/xtribe/xtribepublicgames/directory');
  $folders_repo = json_decode($json);

  $output .= "<ul>";
  $first_time = true;
  $is_empty_repo = true;
  foreach($folders_repo->values as $folder){
    if (strpos($folder,'.zip')) {
      $is_empty_repo = false;
      unset($game_path_exploded);
      $game_date=' ';
      $game_client_or_manager=' ';
      $game_filename=' ';

      $game_path_exploded = explode('/',$folder);

      if ($game_path_exploded[0]) {
        if ($game_name!=$game_path_exploded[0]){
          if ($first_time) {
            $first_time=false;
          }else{
            $output .= "</table>";
          }
          $game_name=$game_path_exploded[0];
          $output .= "<br><strong><em style='color:#8AAF45;'><li>".$game_name."</li><br></strong></em>";
          $output .= "<table class='sticky-enabled tableheader-processed sticky-table'><thead><tr>
          <th>Version timestamp</th>
          <th width='25px'>Type</th>
          <th width='25px'>Download</th>
          </tr></thead>";
        }
        $game_name=$game_path_exploded[0];

      }
      if ($game_path_exploded[1]) { $game_date=$game_path_exploded[1];}
      if ($game_path_exploded[2]) { $game_client_or_manager=$game_path_exploded[2];}
      if ($game_path_exploded[3]) { $game_filename=$game_path_exploded[3];}

      //dpm('FOLDER:'.$folder);
      //dpm($game_name.' '.$game_date.' '.$game_client_or_manager.' '.$game_filename);
      $output .= "<tr><td>".$game_date."</td>";
      $output .= "<td>".$game_client_or_manager."</td>";
      //$folders_repo->revision can be used instead of master, but 'master' seems more general to me
      $output .= "</td><td align='center'><a href='https://bitbucket.org/xtribe/xtribepublicgames/raw/master/".$folder."'><img src='http://141.108.5.30/sites/all/themes/etslook/download.png' height='20' width='20'><br></td></tr>";
    }
  }
  if ($is_empty_repo) {
    $output .= "No game shared available.";
  }else{
    $output .= "</table></ul>";
  }
  return $output;
}
// ------------- END XTRIBE SHARED EXPERIMENTS

/*function ets_monitor() {

  //This code is not used at the moment and should be debugged if and when reactivated 
  
drupal_set_title("ETS System monitor");
  
  $v = rand(1, 1000);
  
  $host_port = variable_get('ets_ehs_host_port', 'localhost:6701');

  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/sockjs-0.3.min.js");   //drupal_add_js("http://{$host_port}/socket.io/socket.io.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ETS.js");
  //drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/monitor.js", array('scope' => 'footer'));
  //drupal_add_css(drupal_get_path('module', 'ets') . '/css/monitor.css', array('type' => 'file')); 

#  drupal_add_js(array('ets' => array('mon_host' => variable_get('ets_mon_host', 'localhost'))), 'setting');
#  drupal_add_js(array('ets' => array('mon_port1' => variable_get('ets_mon_port1', '6767'))), 'setting');
  
  $page =<<<EOHTML
  
  <div id="monitor-status"></div>
  <div id="io-panels">

    <div class="log-panels clearfix">
      <div class="term" id="log-EHS"><div class="title">EHS Logs</div><div class="body"></div></div>
      <div class="term" id="log-MHS"><div class="title">MHS Logs</div><div class="body"></div></div>
      <div class="term" id="log-THS"><div class="title">THS Logs</div><div class="body"></div></div>
    </div>
    
    <div class="stats-panels clearfix">
      <div class="term" id="stats-EHS"><div class="title">EHS Stats</div><div class="body"></div></div>
      <div class="term" id="stats-MHS"><div class="title">MHS Stats</div><div class="body"></div></div>
      <div class="term" id="stats-THS"><div class="title">THS Stats</div><div class="body"></div></div>
    </div>
    
  </div>
  
EOHTML;
  $build = array();
  $build['content'][] = array(
    '#markup' => $page
  );
  
  return $build;
  
}*/

/* ---- STRICT MODE PAGE
Page compelling the user to fill fields required in strict mode
*/
function ets_join_experiment_contr_strict_mode() {

  $html='<div class="strict_mode_message">This experiment restricts partecipation to player having some features. Please fill the data required before joining. This data will be added to your profile, if you are already registered to Xtribe, otherwise we will store them anonymously until your registration, to let you play. Please <a href="/user">register</a> to exploit all Xtribe features. <br></div>';

  module_load_include('inc', 'user', 'user.pages');

  global $user;  
  $user = user_load($user->uid);

  $form = drupal_get_form('user_profile_form', $user, 'account', 'strict_mode'); 

  $html=$html.drupal_render($form);

  return $html;
}

function ets_form_user_profile_form_alter(&$form, &$form_state, $form_id){
  global $user;
  $node = node_load(arg(2));
  
  // We use overlay for asking location, but we need to remove the ability to
  // change the "Administrative overlay" option in the profile edit form
  // We should change ets module weight or rely to the (buggy) hook_module_implements_alter
  // I prefer to go hiding the fieldset with javascript
  drupal_add_js(drupal_get_path('module', 'ets') . '/ets-form.js');

  //modifies the form_user_profile in case we called it to fill empty fields in strict mode
  if(isset($form_state['build_info']['args'][2]) && $form_state['build_info']['args'][2] = 'strict_mode'){

   // add a class to the form to do some styling
   $form['#attributes']['class'][] = 'strict_mode_form';

   //rename submit button
   $form['actions']['submit']['#value'] = t("Update and Join The Experiment");
   if ($user->uid!=0) {
     $form['#submit'][] = 'ets_user_profile_form_submit';
   }else{
    // Using a custom function to put data in a temporary location
    $form['#submit'] = array('ets_anonymous_user_profile_form_submit');
    
    // fill with placeholder data just to pass validation on useless field and proceed with custom function
    $form['account']['name']['#value']='anon';
    $form['account']['mail']['#value'] = 'anon@anon.anon';
    $form['account']['pass'] = array(
      '#type' => 'textfield',
      '#title' => t('Password'),
      '#description' => t(''),
      '#default_value' => user_password(8),
    );
   }
   
   // let's hide some unwanted fields
   $form['actions']['cancel']['#access']=FALSE;
   $form['account']['#access']=FALSE;
   $form['username']['#access']=FALSE;
   $form['picture']['#access']=FALSE;   
   $form['field_fullname']['#access']=FALSE;   
   $form['ckeditor']['#access']=FALSE;   

   // Some field are not rendered here, so we hide them in ets_hide_field_user_profile_form
   $form['field_language_sp']['#access']=FALSE;
   $form['field_dob']['#access']=FALSE;
   $form['field_education']['#access']=FALSE;
   $form['field_sex']['#access']=FALSE;

   // let's show field that must be filled
   $conditions = $node->ets_conditions;
   foreach($conditions as $name => $cond) {
      $rc = ets_conditions_check_condition($name, $cond, $user);
      $cond_name = substr($name,0,-2);
      //watchdog('test', 'cond data: '.print_r($name,true)."--------".print_r($cond,true)." rc:".$rc);
      if (ETS_CONDITION_CANT_SAY == $rc) {
        switch ($cond_name) {
          case 'language_sp':
            $lang = $form['field_language_sp']['#language'];
            $form['field_language_sp']['#suffix']='Scroll to choose multiple languages.';       
            $form['field_language_sp']['#access']=TRUE;
            $form['field_language_sp'][$lang]['#required']=TRUE;
            break;
          case 'age':
            array_unshift($form['#validate'], 'date_strict_validate');
            $lang = $form['field_dob']['#language'];
            $form['field_dob']['#access']=TRUE;
            $form['field_dob'][$lang]['#required']=TRUE;
            break;
          case 'education':
            $lang = $form['field_education']['#language'];
            $form['field_education']['#access']=TRUE;
            $form['field_education'][$lang]['#required']=TRUE;
            break;
          case 'sex':
            $lang = $form['field_sex']['#language'];
            $form['field_sex']['#access']=TRUE;
            $form['field_sex'][$lang]['#required']=TRUE;
            break;
          default:
            break;
        }
      }
    }
    //watchdog('test','FORM <pre>'.print_r($form,true).'</pre>');
  }else{
    if (ets_user_can_join($node)) {
      drupal_goto("ets/exp-join/" . arg(2));
    }
  }
}

/*This is called by ets_form_alter in ets.module in case we are on strict mode user_profile_form*/
function ets_hide_field_user_profile_form($form_element, &$form_state) {
  // hide some fields
  $form_element['locations']['#access']=FALSE;
  $form_element['locale']['#access']=FALSE;
  $form_element['timezone']['#access']=FALSE;
  $form_element['overlay_control']['#access']=FALSE;

  return $form_element;
}

// *After* regular submit for authenticated user
function ets_user_profile_form_submit($form, &$form_state) {
  $node = node_load(arg(2));
  // At this time, data have been saved
  if (ets_user_can_join($node)) {
    drupal_goto("ets/exp-join/" . arg(2));
  }else{
    drupal_set_message(t("Sorry, you are not qualified to join this experiment!"),'warning',FALSE);
    drupal_goto('node/'.$node->nid.'/');
  }
}

// Totally custom submit for anomymous users
function ets_anonymous_user_profile_form_submit($form, &$form_state) {
  $node = node_load(arg(2));
  global $user;
  $guid=ets_get_guid();

  $fields_to_update= array(); 

  // SEX
  $lang = $form['field_sex']['#language'];
  $sex = $form_state['values']['field_sex'][$lang][0]['value'];
  if (isset($sex)) {
    $fields_to_update+= array('sex' => $sex); 
  }

  // AGE
  $empty_dob=TRUE;
  $lang = $form['field_dob']['#language'];
  $dob = $form_state['values']['field_dob'][$lang];
  foreach ($dob[0] as $key => $value) {
    if ($key!='value' && $key!='timezone') { unset($dob[0][$key]); }
    if ($key=='value' && !empty($value)){ $empty_dob=FALSE; }
  }
  if (!$empty_dob && $dob) {
    $dob = json_encode($dob); 
    $fields_to_update+= array('dob' => $dob);
  }

  // EDUCATION
  $lang = $form['field_education']['#language'];
  $education = $form_state['values']['field_education'][$lang][0]['value'];
  if ($education) {
    $fields_to_update+= array('education' => $education);
  }

  // SPOKEN LANGUAGE
  $lang = $form['field_language_sp']['#language'];
  $language_sp= array();
  foreach ($form_state['values']['field_language_sp'][$lang] as $key) {
    if(!empty($key['value'])){
      $language_sp[]=$key['value'];
    }
  }
  if ($language_sp) {
    $language_sp = json_encode($language_sp); 
    $fields_to_update+= array('language_sp' => $language_sp); 
  }

  // Save it!
  watchdog("ETS debug", "test <pre>".print_r($fields_to_update,true)."</pre>", array(), WATCHDOG_NOTICE);
  if (!empty($fields_to_update)) {
    db_merge('ets_anon_usr')
    ->key(array('guid' => $guid))
    ->fields($fields_to_update)
    ->execute();
  }

  // At this time, data have been saved
  if (ets_user_can_join($node)) {
    //drupal_set_message('You are Qualified!');
    drupal_goto("ets/exp-join/" . arg(2));
  }else{
    drupal_set_message(t("Sorry, you are not qualified to join this experiment!"),'warning',FALSE);
    drupal_goto('node/'.arg(2).'/');
  } 
}

function date_strict_validate ($form, &$form_state) {
  $lang = $form['field_dob']['#language'];
  $dob = $form_state['values']['field_dob'][$lang];
  foreach ($dob[0] as $key => $value) {
    if ($key=='value' && empty($value)){ 
      form_set_error('field_dob', t('Date of birth is required'));
    }
  }
}
/* ---- END STRICT MODE PAGE */

function ets_join_experiment($exp_node) {
  global $user;

  // This ensure that querystring is being trasnsported with the link
  if ($user->uid == 0 && !ets_get_node_field($exp_node, 'anonymous_join')) {
    drupal_goto('user', array('query'=>drupal_get_destination()));
  }

  if (!ets_user_can_join($exp_node)) {
    drupal_set_message(t("Sorry, you are not qualified to join this experiment!"),'warning',FALSE);
    drupal_access_denied();
    return;
  }

  global $language ;
  $lang_name = $language->language ;
  user_cookie_save(array('clang'=>$lang_name));

  if (isset($_GET['l']) && $user->uid == 0) {
    drupal_set_message(t("Please login before joining the experiment"));
    drupal_goto('user', array('query'=>drupal_get_destination()) );
  }

  add_cache_meta();

  // Dodgy!! If a player doesn't meet requirement for a game but directly access join page
  // gets redirected to the right page, in strict mode
  $path=str_replace("/kreyon", "", current_path()); //strip kreyon part away
  if (ets_url_join($exp_node)!=$path) { 
    drupal_goto(ets_url_join($exp_node), array('query'=>drupal_get_destination()) ); 
  }

  if ($_SERVER['SERVER_NAME'] == 'www.kreyon.net' OR $_SERVER['SERVER_NAME'] == 'kreyon.net' ) { 
    $kreyonProject = '/kreyon/';
  }else{ 
    $kreyonProject = '';
  }
  
  $build = array(
    '#type' => 'page',
    'content' => array(
      '#sorted' => TRUE
    )
  );
 
  $guid = ets_get_guid();
  
  //$token = ets_token_generate($guid);
  //ets_token_save($exp_node->nid, $guid, $token);
  
  $timeout = ets_get_node_field($exp_node, 'join_timeout');
  
  drupal_set_title($exp_node->title);
  
  $v = rand(1, 1000);

  /*
   * $loc_type value meanings:
   * 0: location not used for the experiment
   * 1: location from user profile (if the profile is empty, the $loc_type will be 3)
   * 2: location from GPS
   * 3: location not dislosed
   */

  $loc_type = ETS_LOC_UNUSED;
  $lat = $long = 0;
  $jspos= '';

  if (ets_get_node_field($exp_node, 'geo_required')) {
    
    // To not disclose too much logic, we prepare the JavaScript snippet here
    
    // This happens when you directly open the experiment join page skipping the introductory page
    if (!isset($_SESSION['ets_loc_type'])) {
      $_SESSION['ets_loc_type'] = ETS_LOC_UNKNOWN;
    }
    
    switch($_SESSION['ets_loc_type']) {

      case ETS_LOC_PROFILE:

        $loc = location_load_locations($user->uid, 'uid');
        $lat  = round($loc[0]['latitude'], 6);
        $long = round($loc[0]['longitude'], 6);
        $jspos = <<< EOJS
        /*
          position.required = true;
          position.latitude = parseFloat({$lat});
          position.latitude = parseFloat({$long});
        */
EOJS;
      break;

      case ETS_LOC_GPS:
        $jspos = <<< EOJS
        /*
          position.required = true;
          navigator.geolocation.getCurrentPosition(function(data) {
              position.latitude = data.coords.latitude
              position.longitude = data.coords.longitude
            }, function errorHandler(code) {}
          )
        */
EOJS;
      break;
   
    }
  }

  $exp_url = file_create_url("public://exp_packages/{$v}/{$exp_node->machine_name}");

  $host_port = variable_get('ets_ehs_host_port', 'localhost:6701');
  list($host, $port) = explode(':', $host_port);
  
  $key  = variable_get('ets_key', 'invalidkey');

  drupal_add_js(array('ets_key' => $key), 'setting');
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/sockjs-0.3.min.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ETS.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/JoinShell.js");

  $is_raw = ets_get_node_field($exp_node, 'perform_raw');
  $perform_path = $is_raw ? "exp-perform-raw" : "exp-perform";
  // $perform_path = "exp-perform";
  
  $querystring='';
  if ($_SERVER['QUERY_STRING']!='') {
    $querystring='?'.$_SERVER['QUERY_STRING'];
  }

  $js =<<<EOJS
  <div class="experiment-join">
  <h2>Waiting for the instance to start. Timeout in <span id="elapsed">(calculating...)</span></h2>
  <p id="please-wait">Please wait, user <strong id="userId"></strong>.</p>
  <p id="status"><strong id="nUsers">0</strong> people have joined so far.</a>
  <p><a href="/">Cancel</a></p>
  </div>
  
  <script>
  ;(function($) {

    var position = {required: false, latitude: 0, longitude: 0};

    {$jspos} 
    
    $('#userId').text({$user->uid} === 0 ? 'anonymous' : {$user->uid});

    var eId = {$exp_node->nid};
    
    var joinShell = new ETS.JoinShell();
  
    joinShell.setIds({eId: eId, uId: {$user->uid}, guid: '{$guid}'});

    joinShell.setPosition(position);
    
    joinShell.setChannel(new ETS.Channel('{$host}', {$port}, "ehs"));

    joinShell.on('disconnect', function() {
      $(window).unbind('beforeunload.ets');
      if (this.channel.connected) {
        $('#status').html("The remote end hung up unexpectedly. Experiment aborted.");
        this.channel.close();
        $("#please-wait").slideUp('slow');
        ETS.Drupal.watchdog("ETS Client JOIN", "The remote end hung up unexpectedly", ETS.Drupal.WATCHDOG_WARNING);
      }
      joinShell.shutdown();
    })
  
    joinShell.on('tick', function(elapsed) {
      $('#elapsed').text({$timeout} - elapsed);
      if (elapsed > {$timeout}) {
        joinShell.shutdown();
        $('#elapsed').text("Timeout");
        $("#please-wait").slideUp('slow');
        ETS.Drupal.watchdog("ETS Client JOIN", "Timout on join", ETS.Drupal.WATCHDOG_NOTICE);
      }
      if (elapsed>8 && $("#nUsers").text()=='0') {
        joinShell.shutdown();
        $('#elapsed').text("Timeout");
        ETS.Drupal.watchdog("ETS Client JOIN", "Network error on join", ETS.Drupal.WATCHDOG_NOTICE);
        $('#status').html("Sorry, an error occurred while trying to contact the server <a href=''>Retry</a>");
        window.location = window.location.href;
      }
    });
    
    joinShell.on('accept', function(message) {
    });
    
    joinShell.on('status', function(message) {
      if (message.params.exception) {
        joinShell.shutdown();
        $("#status").text(message.params.exception);
        $("#please-wait").slideUp('slow');
      } else {
        $("#nUsers").text(message.params.nUsers + " out of " + message.params.nUsersMin);
      }
    })
    
    joinShell.on('error', function(error) {
      $(window).unbind('beforeunload.ets');
      joinShell.shutdown();
      if ('object' == typeof error) {
        error = error.error
      }
      $('#status').html("Sorry, an error occurred while trying to contact the server (" + error + "). <a href=''>Retry</a>");
      $("#please-wait").slideUp('slow');
      ETS.Drupal.watchdog("ETS Client JOIN", "The server reported an error: " + error, ETS.Drupal.WATCHDOG_ERROR);
    })

    joinShell.on('refuse', function(error) {
      $(window).unbind('beforeunload.ets');
      joinShell.shutdown();
      $('#elapsed').text("Aborted");
      $("#status").text(error);
      $("#please-wait").slideUp('slow');
      if (error) {
        alert("Sorry, the experiment cannot be started: " + ((typeof error == 'object' ? error.message : error)));
        ETS.Drupal.watchdog("ETS Client JOIN", "Experiment cannot be started: " + ((typeof error == 'object' ? error.message : error)), ETS.Drupal.WATCHDOG_WARNING);
      } else { // Unlikely (denotes an error in the server)
        alert("Sorry, the experiment can't be started.\\nTry again in a few minutes.");
        ETS.Drupal.watchdog("ETS Client JOIN", "Experiment cannot be started (no error)", ETS.Drupal.WATCHDOG_WARNING);
      }
    });
    
    joinShell.on('start', function(data) {
      // A new instance has been created. Move the user to the perform page. 
      // Add another second of entropy trying to serialize MHS contacts
      joinShell.shutdown();
      $(window).unbind('beforeunload.ets');
      setTimeout(function() {
        //location.href = ETS.Tools.themedUrl("/ets/{$perform_path}/" + eId + "/" + data.iId + "/{$token}");  
        location.href = ETS.Tools.themedUrl("/ets/{$perform_path}/" + eId + "/" + data.iId + "{$kreyonProject}"+"{$querystring}");          
      }, 0|(Math.random() * 1000));
    });

    joinShell.boot();

    $(window).bind('beforeunload.ets', function(e) {
      var m = "Current experiment will be interrupted"; // Firefox will not show the warning
      if (e) {
        e.returnValue = m;
      }
      // Commenting the following return, disables confirmation on exit while joining
      return m;
    });

  })(jQuery);

  </script>
EOJS;
  
  $build['content'][] = array(
    '#markup' => $js
  );
  
  return $build; 
  
}

function add_cache_meta() {

  $cache_meta = array(
    '#type' => 'html_tag',
    '#tag' => 'meta',
    '#attributes' => array(
      'http-equiv' => 'cache-control',
      'content' =>  'max-age=0'
    )
  );
  drupal_add_html_head($cache_meta, 'cache_meta1');

  $cache_meta = array(
    '#type' => 'html_tag',
    '#tag' => 'meta',
    '#attributes' => array(
      'http-equiv' => 'cache-control',
      'content' =>  'no-cache'
    )
  );
  drupal_add_html_head($cache_meta, 'cache_meta2');

  $cache_meta = array(
    '#type' => 'html_tag',
    '#tag' => 'meta',
    '#attributes' => array(
      'http-equiv' => 'expires',
      'content' =>  '0'
    )
  );
  drupal_add_html_head($cache_meta, 'cache_meta3');

  $cache_meta = array(
    '#type' => 'html_tag',
    '#tag' => 'meta',
    '#attributes' => array(
      'http-equiv' => 'pragma',
      'content' =>  'no-cache'
    )
  );
  drupal_add_html_head($cache_meta, 'cache_meta4');
}

// Creates the experiment page without any drupal layout, reading and
// serving the index.html file of the experiment

// EDIT: presently this function is NOT used anymore. We keep the code for future implementation 
// EDIT 2: fix up the function, it is still used. remove raw management, if this is fixed, from ets_perform_experiment
function ets_perform_experiment_raw($exp_node, $instance_id/*, $token*/) {

  global $user;

  if (!ets_user_can_join($exp_node)) {
    drupal_access_denied();
    return;
  }

  drupal_set_title($exp_node->title);

  $v = rand(1, 1000);
  
  $host_port = variable_get('ets_mhs_host_port1', 'localhost:6721');
  list($host, $port) = explode(':', $host_port);

  //$path_perform_js = base_path(). drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/Perform.js";
  $path_jquery_js = base_path(). drupal_get_path('module', 'ets') . "/jslib/{$v}/jquery-1.11.3.js";
  $path_sock_js = base_path(). drupal_get_path('module', 'ets') . "/jslib/{$v}/sockjs-0.3.min.js";
  $path_ets_js = base_path(). drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ETS.js";
  $path_expshell_js = base_path(). drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ExpShell.js";

  /*if (!_ets_experiment_verify_token($exp_node, $token)) {
    $l = l('join phase', "ets/exp-join/{$exp_node->nid}", array('attributes' => array('id' => 'please-join'), 'query' => array('_' => rand())));
    return "<p>You'll be automatically redirected to the first step through the {$l}.</p>
            <p>Thank you.</p>
            <script>setTimeout(function() { location.href=jQuery('#please-join').attr('href'); }, 100); </script>";
  }*/

  $exp_index = $_SERVER['DOCUMENT_ROOT'] . base_path() . "sites/default/files/exp_packages/{$exp_node->machine_name}/index.html";
  $exp_base = "/sites/default/files/exp_packages/{$exp_node->machine_name}/";

  $content = file_get_contents($exp_index);

  list($host, $port) = explode(':', variable_get('ets_mhs_host_port1', 'localhost:6721'));

  $guid = ets_get_guid();
  $exp_base_tag = "<base href=\"{$exp_base}\">";

  // The definition of this structure is also used in Client.js
  // to understand if we are being executed "raw" or not. If you change 
  // the name of this structure you need also to change that name in Client.js
  $exp_def_js =<<<EOJS
  <script type="text/javascript" src="{$path_jquery_js}"></script> 
  <script type="text/javascript" src="{$path_sock_js}"></script> 
  <script type="text/javascript" src="{$path_ets_js}"></script> 
  <script type="text/javascript" src="{$path_expshell_js}"></script> 
  
  <script>
  var ETS_EXP_DATA = {
    eId: '{$exp_node->nid}',
    iId: '{$instance_id}',
    ended: 'false',
    guid: '{$guid}',
    mhsHost: '{$host}',
    mhsPort: '{$port}'

  };

  ;(function($) {

    var eId = '{$exp_node->nid}'
      , iId = '{$instance_id}'
      , ended = false

    var channel = new ETS.Channel('{$host}', {$port}, "mhs"), 
    expShell = new ETS.ExpShell()

    expShell.setIds({eId: eId, iId: iId, uId: {$user->uid}, guid: '{$guid}'});
    
    expShell.on('abort', function(cb) {
      ETS.Drupal.watchdog("ETS Client PERFORM", "Experiment ended or aborted (" + eId + ")", ETS.Drupal.WATCHDOG_NOTICE);
      ended = true;
      if (cb) {
        cb.call();
      }
    });

    expShell.on('error', function(error) {
      ETS.Drupal.watchdog("ETS Client PERFORM", "The server reported an error: " + error, ETS.Drupal.WATCHDOG_ERROR);
      ended = true;
    });

    expShell.on('disconnect', function() {
      if (this.channel.connected) {
        ETS.Drupal.watchdog("ETS Client PERFORM", "The remote end hung up unexpectedly", ETS.Drupal.WATCHDOG_WARNING);
      }
      ended = true;
    });

    // When triggered by a goTo, we receive a callback from expShell
    expShell.on('over', function(data) {

      var _self = this;

      finalize();

      ended = true;

      function finalize() {
        if (typeof data === 'function') {
          _self.shutdown();
          data.call();
        } else {
          _self.shutdown(data);  
        }
      }
    });

    expShell.setChannel(channel);
    
    // The experiment
    expShell.setExperimentWindow(window);
  
    setTimeout(function() {

      expShell.boot();
      ETS.Drupal.watchdog("ETS Client PERFORM", "Experiment started (" + eId + ")", ETS.Drupal.WATCHDOG_NOTICE);
      $(function() {
        if (typeof window.ETS_BOOT == "function") {
          ETS_BOOT();
        }
      });      
    }, 500); // Take a breath  

  })(jQuery);
  </script>
EOJS;
  //uId: '{$user->uid}',

  // Inject the BASE and the setup js elements in HEAD
  $content = str_replace("<head>", "<head>\n<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n{$exp_base_tag}\n{$exp_def_js}\n", $content);
//<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  print $content;

  exit;
}

/* This function can work in three way, defined by user choiches during experiment creation
- Fullscreen: The experiment will be showed fullscreen. On the top of the page will be displayed an Xtribe toolbar, allowing the user to exit from the game and come back to Xtribe game join page. 
- Standalone: The experiment will be showed fullscreen. No additional graphic will be displayed. Please provide an internal way to exit from game.
- IFRAME dimensions in pixels (Width x Height): The experiment will be showed accordingly to the selected dimensions in an Xtribe windows.
*/
function ets_perform_experiment($exp_node, $instance_id/*, $token*/) {
  $clang='/'.$_COOKIE['Drupal_visitor_clang'];

  global $user;

  if (!ets_user_can_join($exp_node)) {
    drupal_access_denied();
    return;
  }
  
  drupal_set_title($exp_node->title);

  /*if (!_ets_experiment_verify_token($exp_node, $token)) {
    $l = l('join phase', "ets/exp-join/{$exp_node->nid}", array('attributes' => array('id' => 'please-join'), 'query' => array('_' => rand())));
    return "<p>You'll be automatically redirected to the first step through the {$l}.</p>
            <p>Thank you.</p>
            <script>setTimeout(function() { location.href=jQuery('#please-join').attr('href'); }, 100); </script>";
  }*/
  
  $build = array(
    '#type' => 'page',
    'content' => array(
      '#sorted' => TRUE
    )
  );
  
  $v = rand(1, 1000);
  
  $host_port = variable_get('ets_mhs_host_port1', 'localhost:6721');
  list($host, $port) = explode(':', $host_port);

  $key  = variable_get('ets_key', 'invalidkey');

  drupal_add_js(array('ets_key' => $key), 'setting');
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/sockjs-0.3.min.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ETS.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/ETS/ExpShell.js");
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/{$v}/jquery.modialog.js");

  $guid = ets_get_guid();

  $dimensions = strtolower(trim(ets_get_node_field($exp_node, 'dimensions')));

  // is_raw is tha standalone mode
  $is_raw = false; //ets_get_node_field($exp_node, 'perform_raw');

  $fullscreen = false;

  // If the user declared dimensions, use them, otherwise the game will be showed fullscreen or standalone
  if (('fullscreen' == $dimensions) || ($is_raw)) {
    drupal_add_html_head(array('#tag' => 'meta','#attributes' => array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1')), "viewport_zoom");
    $fullscreen = true;
    $dim_width = $dim_height = 100; // Just a number: it will be resized with js
    $scrolling = 'yes';
    if ($is_raw) {
      // Css needed to remove xtribe toolbar and whow the game in standalone mode
      drupal_add_css('.modialog-caption {display: none !important;} #popover {border:0px !important;} iframe {margin-top:0px; margin-bottom:0px;}', array('group' => CSS_THEME, 'type' => 'inline'));
    }
    if ($fullscreen) {
      // was #popover {height:100%; ..}
      drupal_add_css('.modialog-caption {color: white; height: 20px; padding: 5px; background-color: silver; color: #444; position: relative; top: -5px; font-weight: bold; transform: none; left:0; width:100%; margin-left:0;} #popover {width:100%; top:0 !important;} #the_experiment { width:100% !important;} .kreyon_button{margin-right:15px;} ', array('group' => CSS_THEME, 'type' => 'inline'));
      drupal_add_css('.responsive .modialog-caption {width:auto !important; top:0px; left:0px;} .responsive #popover{ top:0 !important; right:0 !important; left:0 !important;} ', array('group' => CSS_THEME, 'type' => 'inline'));
      
    }
  } else {
    list($dim_width, $dim_height) = explode('x', ets_get_node_field($exp_node, 'dimensions'));
    $dim_width = intval(trim($dim_width));
    $dim_height = intval(trim($dim_height));
    $dim_height_mod_cap=$dim_height+50;
    $scrolling = 'yes';

    if (strpos($_SERVER['REQUEST_URI'], 'kreyon') != false) { 
      drupal_add_css('#popover,#the_experiment {width:'.$dim_width.'px !important; height:'.$dim_height.'px !important;} .modialog-caption {top: '.$dim_height_mod_cap.'px !important;}', array('group' => CSS_THEME, 'type' => 'inline'));
    }
  }
  
  if (strpos($_SERVER['REQUEST_URI'], 'kreyon') != false) { 
    $onKreyonProject = true;
    $backString = '';
    $backButtonClass = 'kreyon_button';
    $backButton= '/sites/all/themes/kreyonTheme/images/x_chiusura_on_kreyon.png';
  }else{ 
    $onKreyonProject = false;
    $backString = 'Back to Xtribe';
    $backButtonClass = 'xtribe_button';
    $backButton= '/sites/all/themes/etslook/favicon16.png';
  }
  
  $fullscreen = $fullscreen ? 'true' : 'false';
  if($is_raw){
    $fullscreen='true';
  }

  $exp_url = file_create_url("public://exp_packages/{$v}/{$exp_node->machine_name}");

  $town_data = ets_get_town_data(ets_get_node_field($exp_node, 'geo_town'));  

  $title = check_plain($exp_node->title);

/*if ({$is_raw}) {
    $('#the_experiment').height($(window).height());
    $(window).bind("resize", function() {
      $('#the_experiment').height($(window).height());
    });
  }*/

  $js =<<<EOJS
  
<h2>Performing experiment <span id="expId"></span>, instance <span id="instanceId"></span></h2>
<p id="status">Experiment is starting... please wait</p>

<div id="popover" class="fullscreen_{$fullscreen}">
<iframe id="the_experiment" scrolling="{$scrolling}" width="{$dim_width}" height="{$dim_height}"></iframe>
</div>

<p><a id="perform_again" href="">Perform it again</a></p>

<script>

;(function($) {

  if ({$fullscreen}) {
    //  $('#the_experiment').attr('scrolling', 'yes'); // doesn't work on IE
    $('#the_experiment').attr('width', '100%');
    $('#the_experiment').height($(window).height() - 30);
    $(window).bind("resize", function() {
      $('#the_experiment').height($(window).height()-30);
    });
  }
  

  var eId = '{$exp_node->nid}'
    , iId = '{$instance_id}'
    , ended = false
    , \$exp = $('#the_experiment')
    , \$pop = $('#popover')

  $('#expId').text(eId);
  $('#instanceId').text(iId);

  \$exp.attr('src', "{$exp_url}/index.html?r=" + Math.random());

  // Caching issues
  \$exp.get(0).src = \$exp.get(0).src;

  //$('#perform_again').attr('href', "/ets/exp-join/{$exp_node->nid}");

  var channel = new ETS.Channel('{$host}', {$port}, "mhs")
    , expShell = new ETS.ExpShell()

  expShell.setIds({eId: eId, iId: iId, uId: {$user->uid}, guid: '{$guid}'});

  expShell.on('abort', function(cb) {
    $(window).unbind('beforeunload.ets');
    ETS.Drupal.watchdog("ETS Client PERFORM", "Experiment ended or aborted (" + eId + ")", ETS.Drupal.WATCHDOG_NOTICE);
    ended = true;
    if (cb) {
      cb.call();
    }
  })

  expShell.on('error', function(error) {
    $(window).unbind('beforeunload.ets');
    $('#status').html("Sorry, an error occurred while trying to contact the server (" + error + ")");
    ETS.Drupal.watchdog("ETS Client PERFORM", "The server reported an error: " + error, ETS.Drupal.WATCHDOG_ERROR);
    \$pop.modialog('close');
    ended = true;
  })

  expShell.on('disconnect', function() {
    $(window).unbind('beforeunload.ets');
    if (this.channel.connected) {
      $('#status').html("The remote end hung up unexpectedly. Experiment aborted.");
      ETS.Drupal.watchdog("ETS Client PERFORM", "The remote end hung up unexpectedly", ETS.Drupal.WATCHDOG_WARNING);
    }
    ended = true;
  })

  // When triggered by a goTo, we receive a callback from expShell
  expShell.on('over', function(data) {

    var _self = this;

    $(window).unbind('beforeunload.ets');

    finalize();

    ended = true;

    function finalize() {
      if (typeof data === 'function') {
        _self.shutdown();
        data.call();
      } else {
        _self.shutdown(data);  
      }
    }
  });

  \$exp.load(function() {

    expShell.setChannel(channel);
    
    // The experiment
    expShell.setExperimentWindow(\$exp.get(0).contentWindow);
  
    setTimeout(function() {
      expShell.boot();
      ETS.Drupal.watchdog("ETS Client PERFORM", "Experiment started (" + eId + ")", ETS.Drupal.WATCHDOG_NOTICE);
    }, 500); // Take a breath
    
   // $('#status').html("Experiment is started");
  });

  $('#popover').modialog({
    closeWithEsc: false
    , title: "{$title}"
    , icon: '{$backString} <img class="{$backButtonClass}" src="{$backButton}" style="vertical-align: top">'
    , fullscreen: {$fullscreen}
    , offsetTop: -75
    , onBeforeClose: function() {
      if (ended || confirm("Really exit the experiment?")) {
        $(window).unbind('beforeunload.ets');
        expShell.shutdown();
        if ("{$onKreyonProject}") {
          location.href = ETS.Tools.themedUrl("/kreyon/")
        } else {
          location.href = ETS.Tools.themedUrl("{$clang}/node/{$exp_node->nid}")
        }
      }
      return false;
    }
  }).modialog('open')
  
  if ({$fullscreen}) {
    $('#toolbar').hide();
    $('.navbar').hide();
    $('#main').hide();
  }

  $(window).bind('beforeunload.ets', function(e) {
    var m = "Current experiment will be interrupted"; // Firefox will not show the warning
    if (e) {
      e.returnValue = m;
    }
    return m;
  });
})(jQuery);

</script>
EOJS;
  
  
  $build['content'][] = array(
    '#markup' => $js
  );
  
  return $build; 
  
}

/*
function _ets_experiment_verify_token($node, $token) {

  return true; // remove, TEST DEBUG

  if (ets_get_node_field($node, 'no_token')) { 
    return true;
  }

  if (ets_token_verify($node->nid, $token)) {
    ets_token_spend($node->nid, $token);
    return true;
  }

  return false;
}
*/

function ets_settings_form() {
  
  require_once('ets.redis.inc');
  
  try {
    ets_redis_get("something");
    drupal_set_message(t("REDIS connection succeded"));
  } catch(Exception $e) {
    drupal_set_message(t("Cannot connect to REDIS"), 'warning');
  }
  
  $form = array();

  $form['note1'] = array(
    '#type' => 'item',
    '#description' => "Those settings must match those in the config.js file for the ETS server",
  );

  $form['ets_key'] = array(
    '#type' => 'textfield',
    '#title' => t('Shared key'),
    '#description' => t('This is the key that Drupal and the backend shares to secure their messages.'),
    '#required' => TRUE,
    '#size' => 20,
    '#default_value' => variable_get('ets_key', 'invalidkey')
  );

  $form['ets_redis'] = array(
    '#type' => 'fieldset',
    '#title' => "Redis Settings",
    '#collapsible' => FALSE,
  );

  $form['ets_redis']['redis_host_port'] = array(
    '#type' => 'textfield',
    '#title' => t('Redis Hostname / IP & port'),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_redis_host_port', 'localhost:6379')
  );
  
  /*
  $form['ets_redis']['redis_port'] = array(
    '#type' => 'textfield',
    '#title' => t('Redis Port'),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_redis_port', 6379)
  );
  */
  
  $form['ets_ehs_settings'] = array(
    '#type' => 'fieldset',
    '#title' => "EHS Settings",
    '#collapsible' => FALSE,
  );

  $form['ets_ehs_settings']['ehs_host_port'] = array(
    '#type' => 'textfield',
    '#title' => t('EHS Hostname & Port'),
    '#description' => t("Must match the one in server's config.json"),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_ehs_host_port', 'localhost:6701')
  );
 
  /* 
  $form['ets_ehs_settings']['ehs_port'] = array(
    '#type' => 'textfield',
    '#title' => t('EHS TCP Port'),
    '#description' => t("Must match the one in server's config.json"),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_ehs_port', '6701')
  );
  */

  $form['ets_mhs_settings'] = array(
    '#type' => 'fieldset',
    '#title' => "MHS Settings",
    '#collapsible' => FALSE,
  );

  $form['ets_mhs_settings']['mhs_host_port1'] = array(
    '#type' => 'textfield',
    '#title' => t('Primary MHS Hostname & Port'),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_mhs_host_port1', 'localhost:6721')
  );

  /*  
  $form['ets_mhs_settings']['mhs_port1'] = array(
    '#type' => 'textfield',
    '#title' => t('Primary MHS TCP Port 1 (def: 6721)'),
    '#description' => t("Must match the one in server's config.json"),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_mhs_port1', '6721')
  );
  */
  
  $form['ets_mhs_settings']['mhs_host_port2'] = array(
    '#type' => 'textfield',
    '#title' => t('Secondary MHS TCP hostname & Port'),
    '#description' => t("Used also for the default manager. Must match the one in server's config.json"),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_mhs_host_port2', 'localhost:6722')
  );
  
  $form['ets_mon_settings'] = array(
    '#type' => 'fieldset',
    '#title' => "Monitor Settings",
    '#collapsible' => FALSE,
  );

  $form['ets_mon_settings']['mon_host_port'] = array(
    '#type' => 'textfield',
    '#title' => t('Monitor Hostname & Port'),
    '#required' => TRUE,
    '#size' => 15,
    '#default_value' => variable_get('ets_mon_host_port', 'localhost:6767')
  );
  
  /*
  $form['ets_mon_settings']['mon_port'] = array(
    '#type' => 'textfield',
    '#title' => t('Monitor TCP Port'),
    '#required' => TRUE,
    '#size' => 15,
    '#description' => t("Must match the one in server's config.json"),
    '#default_value' => variable_get('ets_mon_port', '6767')
  );
  */
  
/*
 * Default manager is now part of the MHS
 * 
  $form['ets_def_mgr_settings'] = array(
    '#type' => 'fieldset',
    '#title' => "Default manager",
    '#collapsible' => FALSE,
  );

  $form['ets_def_mgr_settings']['def_mgr_uri'] = array(
    '#type' => 'textfield',
    '#title' => t('Default Manager URI'),
    '#required' => TRUE,
    '#size' => 25,
    '#default_value' => variable_get('ets_def_mgr_uri', 'http://localhost:6710')
  );
*/

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Save',
  );
  
  return $form;
}


function ets_settings_form_validate($form, &$form_state) {
  # TODO
  return TRUE; 
}


function ets_settings_form_submit($form, &$form_state) {
  variable_set('ets_key',             trim($form_state['values']['ets_key']));
  variable_set('ets_redis_host_port', trim($form_state['values']['redis_host_port']));
  variable_set('ets_ehs_host_port',   trim($form_state['values']['ehs_host_port']));
  variable_set('ets_mhs_host_port1',  trim($form_state['values']['mhs_host_port1']));
  variable_set('ets_mhs_host_port2',  trim($form_state['values']['mhs_host_port2']));
  variable_set('ets_mon_host_port',   trim($form_state['values']['mon_host_port']));
  drupal_set_message(t("ETS Settings has been saved"));
}

// This is just a useless, demo page
function ets_random_point_page($exp_node) {

  $town_data = ets_get_town_data(ets_get_node_field($exp_node, 'geo_town'));  
  $radius = ets_get_node_field($exp_node, 'geo_radius');
  
  print_r($town_data);  

  $markers = array(
    array(
      'text'       => 'First Marker',
      'latitude'   => $town_data->latitude,
      'longitude'  => $town_data->longitude,
      'markername' => 'lblue',
    ),
  );
  
  for ($i=0; $i < 20; $i++) {
    $coords = ets_get_random_point($exp_node->nid);
    $markers[] = array(
        'text'       => 'Altro Marker',
        'latitude'   => $coords[0],
        'longitude'  => $coords[1],
        'markername' => 'orange',
    );
  }


  $map_array1 = array(
    'id'          => "my-map",         // id attribute for the map
    'width'       => "100%",        // map width in pixels or %
    'height'      => "400px",      // map height in pixels
    'latitude'    => $town_data->latitude,    // map center latitude
    'longitude'   => $town_data->longitude,  // map center longitude
    'zoom'        => 11,              // zoom level
    'maptype'     => "Map",       // baselayer type
    'controltype' => "Small",
    'markers'     =>  $markers,
    'shapes'      => array(
      array(
        'type' => "circle",
        'style' => array("000000", 3, 25, "ffff00", 45),
        'radius' => $radius / 1000,
        'center' => array($town_data->latitude, $town_data->longitude),
      ),
    )

  );
  $element1 = array(
    '#type' => 'gmap',
    '#gmap_settings' => $map_array1,
  );
  $output1 = drupal_render($element1);  
  
  return $output1;
  
}

function ets_get_random_point($nid) {
  
  $exp_node = node_load($nid);
  
  if (!$exp_node) {
    return array();
  }

  $town   = trim(ets_get_node_field($exp_node, 'geo_town'));
  $radius = ets_get_node_field($exp_node, 'geo_radius');

  if (empty($town) || $radius == 0) {
    return array();
  }
  
  $town_data = ets_get_town_data(ets_get_node_field($exp_node, 'geo_town'));  

  // http://www.geomidpoint.com/random/calculation.html
  
  $rnd_radius = rand(0, $radius);
  $rnd_angle  = rand(0, 360);
  $rnd_radius_km = $rnd_radius / 1000;
  
  $d_x = ($rnd_radius_km * cos($rnd_angle)) / 100;
  $d_y = ($rnd_radius_km * sin($rnd_angle)) / 100;
  print $d_x;
  print "<br>";
  print $d_y;
  return array($town_data->latitude + $d_x, $town_data->longitude + $d_y);
}

function ets_show_newsletter() {
  drupal_add_js(drupal_get_path('module', 'ets') . "/jslib/newsletter.js");
  $output='
  <style>
  .google_newsletter {
    background-color: white;
  }
  </style>
  <div class="google_newsletter"><iframe id="forum_embed"
    src="javascript:void(0)"
    scrolling="no"
    frameborder="0"
    width="100%"
    height="700">
    </iframe></div>';
  return $output;
}