<?php /** @file */

require_once('include/zot.php');
require_once('include/crypto.php');


function identity_check_service_class($account_id) {
	$ret = array('success' => false, $message => '');
	
	$r = q("select count(channel_id) as total from channel where channel_account_id = %d ",
		intval($account_id)
	);
	if(! ($r && count($r))) {
		$ret['message'] = t('Unable to obtain identity information from database');
		return $ret;
	} 

	if(! service_class_allows($account_id,'total_identities',$r[0]['total'])) {
		$result['message'] .= upgrade_message();
		return $result;
	}

	$ret['success'] = true;
	return $ret;
}

// Return an error message if the name is not valid. We're currently only checking
// for an empty name or one that exceeds our storage limit (255 chars).
// 255 chars is probably going to create a mess on some pages. 
// Plugins can set additional policies such as full name requirements, character sets, multi-byte
// length, etc. 

function validate_channelname($name) {

	if(! $name)
		return t('Empty name');
	if(strlen($name) > 255)
		return t('Name too long');
	$arr = array('name' => $name);
	call_hooks('validate_channelname',$arr);
	if(x($arr,'message'))
		return $arr['message'];
	return;
}


// Create the system channel for directory synchronisation - this has no account attached


function create_dir_account() {
	create_identity(array(
		'account_id' => 'xxx',  // This will create an identity with an (integer) account_id of 0, but account_id is required
		'nickname' => 'dir',
		'name' => 'Directory',
		'pageflags' => PAGE_DIRECTORY_CHANNEL|PAGE_HIDDEN,
		'publish' => 0
	));
}


function channel_total() {
	$r = q("select channel_id from channel where true");
	if(is_array($r))
		return count($r);
	return false;
}



// Required: name, nickname, account_id

// optional: pageflags

function create_identity($arr) {

	$a = get_app();
	$ret = array('success' => false);

	if(! $arr['account_id']) {
		$ret['message'] = t('No account identifier');
		return $ret;
	}
	$ret=identity_check_service_class($arr['account_id']);
	if (!$ret['success']) { 
		return $ret;
	}
	$nick = mb_strtolower(trim($arr['nickname']));
	$name = escape_tags($arr['name']);
	$pageflags = ((x($arr,'pageflags')) ? intval($arr['pageflags']) : PAGE_NORMAL);

	$name_error = validate_channelname($arr['name']);
	if($name_error) {
		$ret['message'] = $name_error;
		return $ret;
	}

	if(check_webbie(array($nick)) !== $nick) {
		$ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
		return $ret;
	}

	$guid = zot_new_uid($nick);
	$key = new_keypair(4096);


	$sig = base64url_encode(rsa_sign($guid,$key['prvkey']));
	$hash = base64url_encode(hash('whirlpool',$guid . $sig,true));

	// Force a few things on the short term until we can provide a theme or app with choice

	$publish = 1;

	if(array_key_exists('publish', $arr))
		$publish = intval($arr['publish']);

	$primary = true;
		
	if(array_key_exists('primary', $arr))
		$primary = intval($arr['primary']);

	$perms_sql = '';

	$defperms = site_default_perms();
	$global_perms = get_perms();
	foreach($defperms as $p => $v) {
		$perms_keys .= ', ' . $global_perms[$p][0];
		$perms_vals .= ', ' . intval($v);
	}

	$r = q("insert into channel ( channel_account_id, channel_primary, 
		channel_name, channel_address, channel_guid, channel_guid_sig,
		channel_hash, channel_prvkey, channel_pubkey, channel_pageflags $perms_keys )
		values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d $perms_vals ) ",

		intval($arr['account_id']),
		intval($primary),
		dbesc($name),
		dbesc($nick),
		dbesc($guid),
		dbesc($sig),
		dbesc($hash),
		dbesc($key['prvkey']),
		dbesc($key['pubkey']),
		intval($pageflags)
	);
			



	$r = q("select * from channel where channel_account_id = %d 
		and channel_guid = '%s' limit 1",
		intval($arr['account_id']),
		dbesc($guid)
	);

	if(! $r) {
		$ret['message'] = t('Unable to retrieve created identity');
		return $ret;
	}
	
	$ret['channel'] = $r[0];

	if(intval($arr['account_id']))
		set_default_login_identity($arr['account_id'],$ret['channel']['channel_id'],false);

	// Create a verified hub location pointing to this site.

	$r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, 
		hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey )
		values ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )",
		dbesc($guid),
		dbesc($sig),
		dbesc($hash),
		dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()),
		intval(($primary) ? HUBLOC_FLAGS_PRIMARY : 0),
		dbesc(z_root()),
		dbesc(base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey']))),
		dbesc(get_app()->get_hostname()),
		dbesc(z_root() . '/post'),
		dbesc(get_config('system','pubkey'))
	);
	if(! $r)
		logger('create_identity: Unable to store hub location');


	$newuid = $ret['channel']['channel_id'];

	$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_name, xchan_network, xchan_photo_date, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
		dbesc($hash),
		dbesc($guid),
		dbesc($sig),
		dbesc($key['pubkey']),
		dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"),
		dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"),
		dbesc($a->get_baseurl() . "/photo/profile/s/{$newuid}"),
		dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()),
		dbesc(z_root() . '/channel/' . $ret['channel']['channel_address']),
		dbesc(z_root() . '/follow?f=&url=%s'),
		dbesc($ret['channel']['channel_name']),
		dbesc('zot'),
		dbesc(datetime_convert()),
		dbesc(datetime_convert())
	);

	// Not checking return value. 
	// It's ok for this to fail if it's an imported channel, and therefore the hash is a duplicate
		

	$r = q("INSERT INTO profile ( aid, uid, profile_guid, profile_name, is_default, publish, name, photo, thumb)
		VALUES ( %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s') ",
		intval($ret['channel']['channel_account_id']),
		intval($newuid),
		dbesc(random_string()),
		t('Default Profile'),
		1,
		$publish,
		dbesc($ret['channel']['channel_name']),
		dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"),
		dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}")
	);

	$r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_flags )
		values ( %d, %d, '%s', %d, '%s', '%s', %d ) ",
		intval($ret['channel']['channel_account_id']),
		intval($newuid),
		dbesc($hash),
		intval(0),
		dbesc(datetime_convert()),
		dbesc(datetime_convert()),
		intval(ABOOK_FLAG_SELF)
	);

	if(intval($ret['channel']['channel_account_id'])) {

		// Create a group with no members. This allows somebody to use it 
		// right away as a default group for new contacts. 

		require_once('include/group.php');
		group_add($newuid, t('Friends'));

		call_hooks('register_account', $newuid);
	
		proc_run('php','include/directory.php', $ret['channel']['channel_id']);
	}

	$ret['success'] = true;
	return $ret;

}

// set default identity for account_id to channel_id
// if $force is false only do this if there is no current default

function set_default_login_identity($account_id,$channel_id,$force = true) {
	$r = q("select account_default_channel from account where account_id = %d limit 1",
		intval($account_id)
	);
	if($r) {
		if((intval($r[0]['account_default_channel']) == 0) || ($force)) {
			$r = q("update account set account_default_channel = %d where account_id = %d limit 1",
				intval($channel_id),
				intval($account_id)
			);
		}
	}
}

function identity_basic_export($channel_id) {

	/*
	 * Red basic channel export
	 */

	$ret = array();

	$ret['compatibility'] = array('project' => RED_PLATFORM, 'version' => RED_VERSION, 'database' => DB_UPDATE_VERSION);

	$r = q("select * from channel where channel_id = %d limit 1",
		intval($channel_id)
	);
	if($r)
		$ret['channel'] = $r[0];

	$r = q("select * from profile where uid = %d",
		intval($channel_id)
	);
	if($r)
		$ret['profile'] = $r;

	$xchans = array();
	$r = q("select * from abook where abook_channel = %d ",
		intval($channel_id)
	);
	if($r) {
		$ret['abook'] = $r;

		foreach($r as $rr)
			$xchans[] = $rr['abook_xchan'];
		stringify_array_elms($xchans);
	}

	if($xchans) {
		$r = q("select * from xchan where xchan_hash in ( " . implode(',',$xchans) . " ) ");
		if($r)
			$ret['xchan'] = $r;
		
		$r = q("select * from hubloc where hubloc_hash in ( " . implode(',',$xchans) . " ) ");
		if($r)
			$ret['hubloc'] = $r;
	}

	$r = q("select * from `group` where uid = %d ",
		intval($channel_id)
	);

	if($r)
		$ret['group'] = $r;

	$r = q("select * from group_member where uid = %d ",
		intval($channel_id)
	);
	if($r)
		$ret['group_member'] = $r;

	$r = q("select * from pconfig where uid = %d",
		intval($channel_id)
	);
	if($r)
		$ret['config'] = $r;


	$r = q("select type, data from photo where scale = 4 and profile = 1 and uid = %d limit 1",
		intval($channel_id)
	);

	if($r) {
		$ret['photo'] = array('type' => $r[0]['type'], 'data' => base64url_encode($r[0]['data']));
	}


	return $ret;
}



function identity_basic_import($arr, $seize_primary = false) {

	$ret = array('result' => false );

	if($arr['channel']) {
		// import channel		

		// create a new xchan (if necessary)

		// create a new hubloc and seize control if applicable


	}
	if($arr['profile']) {
		// FIXME - change profile assignment to a hash instead of an id we have to fix


	}

	if($arr['xchan']) {

		// import any xchan and hubloc which are not yet available on this site
		// Unset primary for all other hubloc on our own record if $seize_primary


	}

	if($arr['abook']) {
		// import the abook entries


	}


	if($seize_primary) {

		// send a refresh message to all our friends, telling them we've moved

	}


	$ret['result'] = true ;
	return $ret;


}