<?php
# Oauth Client
namespace Oauth\Lib;

use Dever;
use Dever\Session\Oper as Save;
use Passport\Lib\Base;

class Client extends Base
{
	/**
	 * @desc prefix
	 * @var string
	 */
	private $prefix = 'v3_';

	/**
	 * @desc account
	 * @var int
	 */
	private $account = 1;

	/**
	 * @desc save
	 * @var object
	 */
	protected $session = null;

	/**
	 * @desc passport
	 * @var object
	 */
	protected $passport = null;

	/**
	 * @desc request
	 * @var array
	 */
	private $request = null;

	/**
	 * @desc config
	 * @var array
	 */
	private $config = null;

	public function __construct()
	{
		parent::__construct();
		$this->initPassport();
		$this->initSave();
		$this->initRequest();
		$this->initAccount();
		$this->initSource();
        $this->initSystem();
		$this->initSourceType();
		$this->initRefer();
		$this->initConfig();
	}

	private function initPassport()
	{
		$this->passport = Dever::load('passport/lib/base');
	}

	private function initSave()
	{
		$this->session = new Save(DEVER_PROJECT, 'session');
	}

	private function initRequest()
	{
		$this->request = Dever::input();
	}

	private function initAccount()
	{
		$this->account = (isset($this->request['account']) && $this->request['account']) ? $this->request['account'] : $this->session->get($this->prefix . 'oauth_account');
		$this->session->add($this->prefix . 'oauth_account', $this->account);
	}

	private function initSystem()
	{
		$this->system = (isset($this->request['system']) && $this->request['system']) ? $this->request['system'] : $this->session->get($this->prefix . 'oauth_system');
		$this->session->add($this->prefix . 'oauth_system', $this->system);
	}

	private function initSourceType()
	{
		$this->source_type = (isset($this->request['source_type']) && $this->request['source_type']) ? $this->request['source_type'] : $this->session->get($this->prefix . 'oauth_source_type');
		$this->session->add($this->prefix . 'oauth_source_type', $this->source_type);
	}

	private function initSource()
	{
		$this->source = (isset($this->request['source']) && $this->request['source']) ? $this->request['source'] : $this->session->get($this->prefix . 'oauth_source');
		$this->session->add($this->prefix . 'oauth_source', $this->source);
	}

	private function initRefer()
	{
		$this->refer = (isset($this->request['refer']) && $this->request['refer']) ? $this->request['refer'] : $this->session->get($this->prefix . 'oauth_refer');
		$this->session->add($this->prefix . 'oauth_refer', $this->refer);
	}

	private function initConfig()
	{
		$this->config = Dever::db('oauth/account')->one($this->account);
		if (!$this->config) {
			Dever::alert('账户错误');
		}
		$this->config += Dever::config($this->config['type'])->cAll;
	}

	/**
	 * @desc oauth请求
	 */
	public function auth()
	{
		$info = $this->info();
		if ($info) {
			if ($this->refer) {
				$refer = urldecode($this->refer);
				Dever::location($refer);
			} else {
				return true;
			}
		}
		$id = Dever::id();
		$this->session->add($this->prefix . 'oauth_id', $id);
		$this->param('auth', 'appid', $this->config['appid']);
		$this->param('auth', 'redirect_uri', Dever::url('request.callback?account=' . $this->account, 'oauth'));
		$this->param('auth', 'state', $id);
		$this->param('auth', 'response_type');
		$this->param('auth', 'scope');
		
		//print_r($this->config['auth']);die;

		$url = $this->config['auth']['url'] . '?' . http_build_query($this->config['auth']['param']);

		Dever::location($url);
	}
	
	/**
	 * @desc oauth请求 callback
	 */
	public function callback($url = '')
	{
		$this->js = true;
		if ((isset($this->request['js']) && $this->request['js'])) {
			$this->js = false;
		}
		if ($this->js == true && $url) {
			return $this->output($url);
		} else {
			$id = $this->session->get($this->prefix . 'oauth_id');
			if (isset($this->config['token']['param'])) {
				if (!$this->session->get($this->prefix . 'oauth_refresh')) {
					$this->param('token', 'code');
					$this->param('token', 'appid', $this->config['appid']);
					$this->param('token', 'secret', $this->config['appsecret']);
					$this->param('token', 'grant_type');

					$result = Dever::curl($this->config['token']['url'], $this->config['token']['param']);

					$result = Dever::json_decode($result);

					if (isset($result['errmsg'])) {
						Dever::alert($result['errmsg']);
					}

					parse_str(http_build_query($result), $this->request);

					$this->response('token', 'access_token');
					$this->response('token', 'expires_in');
					$this->response('token', 'refresh_token');
					$this->response('token', 'openid');
					$this->response('token', 'unionid');
					$this->response('token', 'scope');
					$this->response('token', 'errcode');
					$this->response('token', 'errmsg');

				} else {
					# 由于refresh token是长期有效的,所以这里无需再次获取了。之后通过这个refresh获取access token就行了
					return;
				}
			}
			
			if (isset($this->config['token']['response']) && $this->config['token']['response']) {
				# 进入绑定流程吧
				return $this->bind();
			}
		}
		Dever::alert('登录失败');
	}
	
	/**
	 * @desc 重新获取token 暂时不用
	 * @author leo(suwi.bin)
	 * @date 2012-08-27
	 */
	protected function refresh()
	{
		$data = $this->request;
		$state = false;
		if(isset($data['token_refresh']) && $data['token_refresh'])
		{
			$this->param('refresh', 'refresh_token',		 $data['token_refresh']);
			$this->param('refresh', 'client_id',			 $this->_config['id']);
			$this->param('refresh', 'client_secret',		 $this->_config['key']);
			$return = json_decode($this->_curl('post', $this->param['refresh']), true);
			if(isset($return['error']))
			{
				Dever::alert('参数错误');
			}
			if(isset($return['access_token']) && $return['access_token'])
			{
				$update['token_code'] = $return['access_token'];
				$update['token_type'] = $return['token_type'];
				$update['token_time'] = $return['expires_in'];
				$state = $this->update($update, $data['id']);
			}
		}
		return $state;
	}
	
	/**
	 * @desc 绑定数据
	 */
	private function bind()
	{
		$data = $this->config['token']['response'];

		if (!$data) {
			Dever::alert('错误的数据');
		}
		
		$get = $this->request;
		
		$id = false;
		
		if (isset($get['id']) && $get['id'] > 0) {
			$id = $get['id'];
		}
		
		$user = $this->update($data, $id);
		# 跳转吧,从哪来去哪吧
		if ($this->refer) {
			$refer = urldecode($this->refer);
			Dever::location($refer);
		} else {
	        return $user;
		}
	}

	/**
	 * @desc 绑定数据
	 */
	private function update($data, $id)
	{
        $this->param('user', 'access_token', $data['access_token']);
		$this->param('user', 'openid', $data['openid']);

		$userinfo = Dever::json_decode(Dever::curl($this->config['user']['url'], $this->config['user']['param']));
		if (!$userinfo) {
			return;
		}
		
        //$user['bind'] = 1;
        $user['temp'] = 2;
        //$user['username'] = Dever::emoji($userinfo['nickname']);
        $user['username'] = $userinfo['nickname'];
        if ($userinfo['headimgurl']) {
            //$update['set_avatar'] = $this->sessionAvatar($pic);
          	$user['avatar'] = $userinfo['headimgurl'];
        }
        
        if ($userinfo['city']) {
            $user['city'] = $userinfo['city'];
        }

        if ($userinfo['province']) {
            $user['province'] = $userinfo['province'];
        }

        if ($userinfo['country']) {
            $user['country'] = $userinfo['country'];
        }

    	$user = $this->passport->wechat($data, $user, $this->account, $this->system, $this->source_type, $this->source);

        return $user;
	}
	
	/**
	 * @desc 输出js内容
	 */
	private function output($url)
	{
		$html = 
		'<script>   
			var params = {}, queryString = location.hash.substring(1),
			regex = /([^&=]+)=([^&]*)/g, m;
			while (m = regex.exec(queryString))
			{
				params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
			}

			location.href="'.$url.'&js=false&" + queryString;
		</script>';
		echo $html;die;
	}
	
	/**
	 * @desc 请求参数
	 */
	private function param($type, $key, $value = false)
	{
		$this->compatible($this->config[$type]['param'], $key, $value);
	}

	/**
	 * @desc 响应参数
	 */
	private function response($type, $key, $value = false)
	{
		$this->compatible($this->config[$type]['response'], $key, $value);
	}

	/**
	 * @desc 兼容处理
	 */
	private function compatible(&$param, $key, $value = false)
	{
		$default = false;
		if (isset($param[$key]) && is_array($param[$key])) {
			$nkey = $param[$key][0];
			$default = $param[$key][1];
			unset($param[$key]);
			$key = $nkey;
		} else {
			$default = $param[$key];
		}
		return $param[$key] = ($value ? $value : (isset($this->request[$key]) ? $this->request[$key] : $default));
	}
}