<?php
class BlockTable {
	function __construct() {
		$this->filter = Setting::Get('block_filter');
		$this->block  = Setting::Get('block_action');
	}

	function updateCache() {
		include 'db.inc.php';
		$block_tables = $db->select('block_tables', NULL, array('key_field' => 'rule_id'));

		$this->filter = array();
		$this->filter['ip'] = array();
		$this->filter['target'] = array();
		$this->filter['action'] = array();
		$this->filter['id'] = array();
		$this->filter['user_id'] = array();
		$this->filter['target_id'] = array();
		$this->filter['target_key'] = array();
		$this->filter['detail'] = array();

		$this->block = array();

		foreach ($block_tables as $k => $rule) {
			if (! is_null($rule['ip']))
				$this->filter['ip'][$k]         = $rule['ip'];
			if (! is_null($rule['id']))
				$this->filter['id'][$k]         = $rule['id'];
			if (! is_null($rule['target']))
				$this->filter['target'][$k]     = $rule['target'];
			if (! is_null($rule['action']))
				$this->filter['action'][$k]     = $rule['action'];
			if (! is_null($rule['user_id']))
				$this->filter['user_id'][$k]    = $this->createNumberRule($rule['user_id']);
			if (! is_null($rule['target_id']))
				$this->filter['target_id'][$k]  = $this->createNumberRule($rule['target_id']);
			if (! is_null($rule['target_key']))
				$this->filter['target_key'][$k] = $rule['target_key'];
			if (! is_null($rule['detail']))
				$this->filter['detail'][$k]     = $rule['detail'];
			$this->block[$k]                    = array(
				'block' => $rule['block'],
				's' => $rule['rule_start'] ? strtotime($rule['rule_start']) : NULL,
				'e' => $rule['rule_end'] ? strtotime($rule['rule_end']) : NULL
			);
		}

		//ダイエット
		foreach ($this->filter as $k => $filter)
			if (empty($filter))
				unset($this->filter[$k]);

		Setting::Set('block_filter', $this->filter);
		Setting::Set('block_action', $this->block);
	}

	function clear() {
		Setting::Del('block_tables');
	}

	function createNumberRule($v) {
		$s = substr($v, 0, 1);
		if ($s == '>') {
			return array(
				't' => 'o',
				'v' => (int)substr($v, 1)
			);
		} else if ($s == '<') {
			return array(
				't' => 'u',
				'v' => (int)substr($v, 1)
			);
		} else if ($s == '!') {
			return array(
				't' => 'n',
				'v' => (int)substr($v, 1)
			);
		}

		@list($from, $to) = explode(':', $v);
		if (empty($to)) {
			return array(
				't' => 'm',
				'v' => (int)$v
			);
		}

		return array(
			't' => 'b',
			'v1' => (int)$from,
			'v2' => (int)$to
		);
	}

	function match($actionObj) {
		$block = $this->block;
		$t = time();
		foreach ($block as $rule_id => $b) {
			if ($b['s'] && $b['s'] > $t) {
				unset($block[$rule_id]);
				continue;
			}
			if ($b['e'] && $b['e'] < $t) {
				unset($block[$rule_id]);
				continue;
			}
		}

		foreach ($actionObj->data as $k => $v) {
			if (! array_key_exists($k, $this->filter))
				continue;

			foreach ($block as $rule_id => $b) {
				if (! array_key_exists($rule_id, $this->filter[$k]))
					continue;
				if (! $this->_match($v, $this->filter[$k][$rule_id]))
					unset($block[$rule_id]);
			}
		}
		if (empty($block))
			return FALSE;

		return $block;
	}

	function _match($v, $filter) {
		if (is_array($filter)) {	//number match
			if (is_null($v))
				return FALSE;

			$v = (int)$v;
			switch ($filter['t']) {
			case 'o':
				return $v > $filter['v'];
			case 'u':
				return $v < $filter['v'];
			case 'n':
				return $v != $filter['v'];
			case 'm':
				return $v == $filter['v'];
			default:
				return $v >= $filter['v1'] && $v <= $filter['v2'];
			}
		}

		return preg_match($filter, $v) === 1;
	}

	function autoDelete() {
		include 'db.inc.php';
		$sql = 'delete from '.$db->getTableName('block_tables'). ' where rule_end is not null and rule_end < CURRENT_TIMESTAMP';
		$ret = $db->query($sql);
		if ($ret === FALSE)
			return;

		if ($ret->rowCount() > 0)
			$this->updateCache();
	}

	function del($id) {
		include 'db.inc.php';
		return $db->delete('block_tables', array('rule_id' => $id));
	}

	function modify($id, $values) {
		include 'db.inc.php';
		return $db->update(
			'block_tables',
			array(
				'name' => @$values['name'],
				'block' => @$values['block'],
				'target' => empty($values['target']) ? NULL : $values['target'],
				'action' => empty($values['action']) ? NULL : $values['action'],
				'ip' => empty($values['ip']) ? NULL : $values['ip'],
				'id' => empty($values['id']) ? NULL : $values['id'],
				'user_id' => empty($values['user_id']) ? NULL : $values['user_id'],
				'target_id' => empty($values['target_id']) ? NULL : $values['target_id'],
				'target_key' => empty($values['target_key']) ? NULL : $values['target_key'],
				'detail' => empty($values['detail']) ? NULL : $values['detail'],
				'rule_start' => empty($values['rule_start']) ? NULL : $values['rule_start'],
				'rule_end' => empty($values['rule_end']) ? NULL : $values['rule_end'],
				'modified' => '^CURRENT_TIMESTAMP'
			),
			array('rule_id' => $id)
		);
	}

	function create($values) {
		include 'db.inc.php';
		return $db->insert(
			'block_tables',
			array(
				'name' => @$values['name'],
				'block' => @$values['block'],
				'target' => empty($values['target']) ? NULL : $values['target'],
				'action' => empty($values['action']) ? NULL : $values['action'],
				'ip' => empty($values['ip']) ? NULL : $values['ip'],
				'id' => empty($values['id']) ? NULL : $values['id'],
				'user_id' => empty($values['user_id']) ? NULL : $values['user_id'],
				'target_id' => empty($values['target_id']) ? NULL : $values['target_id'],
				'target_key' => empty($values['target_key']) ? NULL : $values['target_key'],
				'detail' => empty($values['detail']) ? NULL : $values['detail'],
				'rule_start' => empty($values['rule_start']) ? NULL : $values['rule_start'],
				'rule_end' => empty($values['rule_end']) ? NULL : $values['rule_end'],
				'created' => '^CURRENT_TIMESTAMP',
				'modified' => '^CURRENT_TIMESTAMP'
			)
		);
	}

	function read($id) {
		include 'db.inc.php';
		return $db->selectRow('block_tables', NULL, array('rule_id' => $id));
	}

	function get($limit=NULL) {
		include 'db.inc.php';
		return $db->select('block_tables', NULL, array('limit' => $db->safeLimit($limit)));
	}

	function count() {
		include 'db.inc.php';
		return $db->count('block_tables');
	}
}
