Skip to content

Instantly share code, notes, and snippets.

@kohenkatz
Created December 18, 2012 21:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kohenkatz/4332062 to your computer and use it in GitHub Desktop.
Save kohenkatz/4332062 to your computer and use it in GitHub Desktop.
<?php defined('SYSPATH') OR die('No direct access allowed.');
class Model_ActionPlan extends Mongo_Document
{
/**
* The name of the collection within the database.
*
* @var string
*/
protected $name;
/**
* Use the after_load function to check for whether this AP has expired
*/
protected function after_load()
{
// If we don't have info needed to expire this AP, then don't try
if ( ! isset($this->game_id))
return;
if ($this->is_expired())
{
$game = new Model_Game($this->game_id);
$user = Auth::current_user();
$this->close($game, $user, 'failure');
}
}
public function __construct($name = NULL, $id = NULL)
{
if ($name !== NULL)
{
$this->name = 'Stocks.'.$name.'.action_plans';
}
if ($id !== NULL)
{
parent::__construct($id);
}
}
public function is_expired()
{
if (isset($this->expires))
{
$date = self::date_field($this->expires);
if ($date == null)
return false;
return ($date < time());
}
return false;
}
public function close($game, $user, $close_type, $auto_close = false)
{
// First, if this idea has not yet expired, that means it is being closed manually. In that case,
// make sure that this user is a gamemaster. Only gamemasters can close APs.
if ((! $auto_close) AND ($close_type !== 'failure') AND ( ! $this->is_expired()) AND ! $user->is_gamemaster_in_game($game->id))
{
return;
}
// Now do the payout
if ($game->config['prediction_market']['ActionPlan'])
{
// For now, you can change a failed AP to success but you cannot change a
// successful one to a fail because it will be hard to remove the awarded points.
if (isset($this->status))
{
$status = $this->status; // This crashes
// $status = parent::__get('status'); // This works
if (($status === "closed") AND ($this->close_type != "failure"))
{
return;
}
}
// Now, get all users who own stock in this AP
$owners = $this->owners;
// Can be 'implemented' or 'failed'
switch ($close_type)
{
case 'successful':
// MAX[10, (c * question_score)]
$c = $game->config['prediction_market']['c'];
$payout_per_share = max(10, $c * $this->score);
foreach ($owners as $owner_id => $quantity)
{
$owner = new Model_User(new MongoId($owner_id));
if ($quantity > 0)
{
$owner->inc('points', $payout_per_share * $quantity);
}
else
{
// If this user short-sold shares (meaning that the quantity
// is negative), the spec says that the buyback price
// is always 10, no matter what the payback other users get is.
$owner->inc('points', 10 * $quantity);
}
$owner->save();
}
break;
case 'failure':
// No payout, but we should keep this here for consistency.
break;
default:
throw new InvalidArgumentException("Invalid parameter to close action plan.");
}
}
$this->status = "closed";
$this->close_type = $close_type;
$this->save();
// If this is closed as a success, close it's parent question and all of its
// sibling action plans as failures.
if ($close_type == 'successful')
{
$parent_question = new Model_Question($game->short_name, $this->parent_id);
$parent_question->close($game, $user, 'automatic');
}
}
/**
* Mark an Action Plan as implemented
*/
public function implement($game, $user)
{
// First, stop if this idea has not yet expired or already been implemented.
// Also, only gamemasters can implement APs.
if ($this->is_expired() OR ($this->status == 'implemented') OR (! $user->is_gamemaster_in_game($game->id)))
{
return false;
}
$this->status = "implemented";
$this->save();
return true;
}
private static function date_field($field)
{
if (is_string($field) && strlen($field) > 0)
{
return strtotime($field);
}
elseif ($field instanceof MongoDate)
{
return $field->sec; // we don't care about anything more specific than the seconds.
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment