<?php

require_once('ErrorDebug.php');
require_once('URCValues.php');


class TwowaySysParamGenerator {

	var $rooms = null;
	var $twoway_devices = null;

	function __construct(&$rooms) {		
		$this->rooms = $rooms;
	}

	public function getRooms() {
		return $this->rooms;
	}
	
	public function gather() {

		$this->twoway_devices = array();
		
		$lenRoom = 0;
		if($this->rooms) $lenRoom = count($this->rooms);

		if($lenRoom <= 0) {
			return;
		}

		$roomIds = array();		
		for($i = 0; $i < $lenRoom; $i++) {
			$roomIds[] = $this->rooms[$i]->id;
		}		
		$twoway_devices = DB::table('a_twoway_devices')->whereIn('room_id', $roomIds)->orderBy('id', 'asc')->get();

		//get db_twoway_devices
		$db_twowayDevIdsAll = array();
		foreach($twoway_devices as $tdevice) {
			$db_twowayDevIdsAll[] = $tdevice->model_id;
		}
		$db_twowayDevIds = array_unique($db_twowayDevIdsAll);
		if(count($db_twowayDevIds) > 0) {
			$db_twowayModels = DB::table('a_db2_models')->whereIn('id', $db_twowayDevIds)->get();
		}
		else {
			$db_twowayModels = array();
		}

		//apply parameter
		$fake_ip_val = 100;
		foreach($twoway_devices as $tDevice) {

			$this->applySystemParam($tDevice, $db_twowayModels);

			if($tDevice->model === 'TRF-ZW1') {

				$tDevice->target_info = '0.0.0.1:0';
			}
			else {

				$target_type = $tDevice->target_type & 0xffff;
				if($target_type != URCValues::TWOWAY_TYPE_IP) {

					$tDevice->target_info = $this->getSameParamFakeIP($tDevice, $target_type);

					if($tDevice->target_info === false) {
						$tDevice->target_info = long2ip($fake_ip_val).':0';
						$fake_ip_val++;
					}
				}
				else {

					$tDevice->target_info = $tDevice->target_addr;
				}
			}

			$this->twoway_devices[] = $tDevice;
		}
	}

	public function getDevice($deviceId, &$retDevice) {

		foreach($this->twoway_devices as $tDevice) {
			if($tDevice->id ===  $deviceId) {
				$retDevice = $tDevice;
				return true;
			}
		}
		return false;
	}

	protected function applySystemParam(&$device, &$dbModels) {
		
		foreach($dbModels as $dbModel) {
			if($dbModel->id != $device->model_id) {
				continue;
			}

			$device->script = $dbModel->script;
			$device->parameter = $dbModel->parameter;
			
			//parameter converter
			if(strlen($device->parameter) > 0) {
				$variables = json_decode($device->variables);
				$varCnt = count($variables);
				for($i = 0; $i < $varCnt; $i++) {

					if(!isset($variables[$i]->name) || !isset($variables[$i]->value)) {
						$varCnt = 0;
						break;
					}
				}
				if($varCnt > 0) {					
					foreach($variables as $variable) {
						$device->parameter = str_replace('<<'.$variable->name.'>>', $variable->value, $device->parameter);
					}
				}
			}
			break;
		}	
	}

	protected function getSameParamFakeIP($device, $target_type) {

		foreach($this->twoway_devices as $tDevice) {

			if($tDevice->model_id !== $device->model_id) {
				continue;
			}

			if(isset($tDevice->parameter) != isset($device->parameter)) {
				continue;
			}
			if(isset($tDevice->parameter) && $tDevice->parameter !== $device->parameter) {
				continue;
			}

			if($target_type === URCValues::TWOWAY_TYPE_MAC &&
				strcasecmp($tDevice->target_addr, $device->target_addr)) {
				continue;
			}

			return $tDevice->target_info;
		}

		return false;
	}
}


class ClientDataGenerator {

	var $downloadKey = null;
	var $userId = -1;
	var $curSystemId = -1;
	var $curRoomId = -1;

	var $twoway_sys_devices = null;

	var $calcPageId = -1;
	var $calcPageObj = null;

	var $twowaySysParamMgr = null;

	function __construct($userId, $downloadKey, &$twowaySysParamMgr) {		
		$this->userId = $userId;
		$this->downloadKey = $downloadKey;
		$this->twowaySysParamMgr = $twowaySysParamMgr;
	}

	public function saveSystems($filePath) {

		$result = &$this->genSystems();
		if($result == false) {
			return false;
		}

		$file = fopen($filePath,"w");
		if($file == false) {
			return false;
		}
		  		
		$jsonData = json_encode($result);
		fputs ($file, $jsonData);

  		fclose ($file);

  		return true;
	}

	public function saveSystemsToDB(&$systems) {

		$jsonData = json_encode($systems);

		//ErrorDebug::write('saveSystemsToDB');
		//ErrorDebug::write($jsonData);


		$downData = DB::table('a_download')->where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_SYSTEMS)->first();

		$crc = crc32($jsonData);
		$crc_string = sprintf('%u', $crc);

		if($downData) {
			DB::table('a_download')->where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_SYSTEMS)->update(array('data' => $jsonData, 'crc' => $crc_string));
		}
		else {
			DB::table('a_download')->insert(array('id' => $this->userId,
				'type' => URCValues::DOWN_TYPE_CLIENT_SYSTEMS, 'data' => $jsonData, 'crc' => $crc_string));
		}
	}

	public function &genSystems() {

		$systemsObj = new stdClass;
		
		$systemsObj->header = &$this->createSystemsHeader();
		if(!$systemsObj->header)
			return false;

		$systems = DB::table('a_systems')->where('user_id', '=', $this->userId)->get();
		
		$systemsObj->systems = array();
		foreach($systems as $system) {

			$masterMac = "";
			$bstationObj = DB::table('a_bstations')->where('system_id', '=', $system->id)->
				where('master', '=', 1)->first();
			if($bstationObj) {
				$masterMac = $bstationObj->mac;
			}

			$systemsObj->systems[] = (object)array('id' => $system->id, 'name' => $system->name, 'bstation_mac' => $masterMac);
		}

		return $systemsObj;
	}

	protected function &createSystemsHeader() {

		$header = new stdClass;
		$header->version = URCValues::EDITOR_VER;
		$header->comment = '';

		return $header;
	}

	public function saveSystem($filePath, $systemId) {

		$result = &$this->genSystem($systemId);
		if($result == false) {
			return false;
		}

		$file = fopen($filePath,"w");
		if($file == false) {
			return false;
		}
		  		
		$jsonData = json_encode($result);
		fputs ($file, $jsonData);

  		fclose ($file);

  		return true;
	}

	public function saveSystemToDB($systemId, &$system) {

		$jsonData = json_encode($system);

		//ErrorDebug::write('saveSystem:'.$systemId);
		//ErrorDebug::write($jsonData);


		$downData = DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_SYSTEM)->
			where('system_id', '=', $systemId)->get();

		if($downData && count($downData) != 1)
		{
			DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_SYSTEM)->
			where('system_id', '=', $systemId)->delete();

			$downData = null;
		}

		$crc = crc32($jsonData);
		$crc_string = sprintf('%u', $crc);

		if($downData) {
			DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_SYSTEM)->
			where('system_id', '=', $systemId)->update(array('id' => $this->userId, 'data' => $jsonData, 'crc' => $crc_string));
		}
		else {
			DB::table('a_download')->insert(array('id' => $this->userId,
				'type' => URCValues::DOWN_TYPE_CLIENT_SYSTEM, 'system_id' => $systemId, 'data' => $jsonData, 'crc' => $crc_string));
		}
	}

	public function &genSystem($systemId) {

		$systemObj = new stdClass;
		
		$systemObj->header = &$this->createSystemHeader();
		if(!$systemObj->header)
			return false;

		$system = DB::table('a_systems')->where('user_id', '=', $this->userId)->
			where('id', '=', $systemId)->first();
		if(!$system)
			return false;
		
		$systemObj->system = &$this->createSystem($system);
		return $systemObj;
	}

	protected function &createSystemHeader() {

		$header = new stdClass;
		$header->version = URCValues::EDITOR_VER;
		$header->comment = '';
		$header->download_key = $this->downloadKey;

		return $header;
	}

	protected function setCurSystemId($systemId) {

		$this->curSystemId = $systemId;
	}

	public function &createSystem(&$system) {

		$this->setCurSystemId($system->id);

		$systemObj = new stdClass;
		$systemObj->id = $this->curSystemId;
		$systemObj->name = $system->name;
		$systemObj->bstation_mac = '';

		$rooms = $this->twowaySysParamMgr->getRooms();
		$lenRoom = 0;
		if($rooms) $lenRoom = count($rooms);

		$roomIds = array();
		$systemObj->rooms = array();
		for($i = 0; $i < $lenRoom; $i++) {
			$systemObj->rooms[$i] = new stdClass;
			$systemObj->rooms[$i]->name = $rooms[$i]->name;
			$systemObj->rooms[$i]->id = $rooms[$i]->id;
			//$systemObj->rooms[$i]->bstation_mac = $rooms[$i]->bstation;

			$roomIds[] = $rooms[$i]->id;
		}

		if(count($roomIds) > 0) {
			$this->twoway_sys_devices = DB::table('a_twoway_devices')->whereIn('room_id', $roomIds)->where('model', 'TRF-ZW1')->get();
		}
		else
		{
			$this->twoway_sys_devices = array();
		}

		//store master information in the system
		$bstationObj = DB::table('a_bstations')->where('system_id', '=', $this->curSystemId)->
			where('master', '=', 1)->first();
		if($bstationObj) {
			$systemObj->bstation_mac = $bstationObj->mac;
		}
		$systemObj->controller_id = $system->controller_id;

		$systemObj->home_btn_option = $system->home_btn_option;

		return $systemObj;
	}

	public function saveRoom($filePath, $systemId, $roomId) {

		$result = &$this->genRoom($systemId, $roomId);
		if($result == false) {
			return false;
		}

		$file = fopen($filePath,"w");
		if($file == false) {
			return false;
		}
		  		
		$jsonData = json_encode($result);
		fputs ($file, $jsonData);

  		fclose ($file);

  		return true;
	}

	public function saveRoomToDB($systemId, $roomId, $home_btn_option) {

		$result = &$this->genRoom($systemId, $roomId, $home_btn_option);
		if($result == false) {
			return false;
		}

		$jsonData = json_encode($result);

		//ErrorDebug::write('saveRoomToDB:'.$roomId);
		//ErrorDebug::write($jsonData);

		$downData = DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_ROOM)->
			where('system_id', '=', $systemId)->
			where('room_id', '=', $roomId)->get();

		if($downData && count($downData) != 1)
		{
			DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_ROOM)->
			where('system_id', '=', $systemId)->
			where('room_id', '=', $roomId)->delete();

			$downData = null;
		}

		$crc = crc32($jsonData);
		$crc_string = sprintf('%u', $crc);

		if($downData) {
			DB::table('a_download')->//where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_CLIENT_ROOM)->
			where('system_id', '=', $systemId)->
			where('room_id', '=', $roomId)->update(array('id' => $this->userId, 'data' => $jsonData, 'crc' => $crc_string));
		}
		else {
			DB::table('a_download')->insert(array('id' => $this->userId,
				'type' => URCValues::DOWN_TYPE_CLIENT_ROOM, 'system_id' => $systemId, 
				'room_id' => $roomId, 'data' => $jsonData, 'crc' => $crc_string));
		}

		return true;
	}

	protected function setCurRoomId($roomId) {

		$this->curRoomId = $roomId;
	}

	public function &genRoom($systemId, $roomId, $home_btn_option) {

		$this->setCurSystemId($systemId);		

		$roomObj = new stdClass;

		$room = DB::table('a_rooms')->where('system_id', '=', $this->curSystemId)->
			where('id', '=', $roomId)->first();
		if(!$room)
			return false;

		$this->setCurRoomId($roomId);

		$roomObj->header = &$this->createRoomHeader($room);
		if(!$roomObj->header)
			return false;
		$roomObj->header->home_btn_option = $home_btn_option;

		//schedule events
		$roomObj->schedule_event = &$this->createScheEvents($room);
		
		//devices
		$roomObj->devices = array();
		$devices = DB::table('a_devices')->where('room_id', '=', $room->id)->get();
		
		foreach($devices as $device) {
			$roomObj->devices[] = &$this->createDevice($device, $room->main_device_id === $device->id, $devices);
		}
		
		foreach($roomObj->devices as $device) {
			$this->applyPunchDevice($device, $roomObj->devices);
		}

		//room twoway devices
		$twoway_devices = DB::table('a_twoway_devices')->where('room_id', '=', $room->id)->get();

		//get db_twoway_devices
		$db_twowayDevIdsAll = array();
		foreach($twoway_devices as &$tdevice) {
			$db_twowayDevIdsAll[] = $tdevice->model_id;
		}
		foreach($this->twoway_sys_devices as &$tdevice) {
			if($tdevice->room_id == $room->id) {
				continue;
			}
			$db_twowayDevIdsAll[] = $tdevice->model_id;
		}
		$db_twowayDevIds = array_unique($db_twowayDevIdsAll);

		if(count($db_twowayDevIds) > 0) {
			//$db_twowayModels = DB::table('a_db2_models')->whereIn('id', $db_twowayDevIds)->get();

			$db_twowayModels = DB::table('a_db2_models')->join('a_db2_brands', function($join)
			{
				$join->on('a_db2_models.brand_id', '=', 'a_db2_brands.id');
			})->whereIn('a_db2_models.id', $db_twowayDevIds)->
			select('a_db2_models.id','a_db2_models.brand_id',
				'a_db2_models.major','a_db2_models.version','a_db2_models.name',
				'a_db2_models.target_type','a_db2_models.script','a_db2_models.variables',
				'a_db2_models.parameter','a_db2_models.twoway_modules', 'a_db2_brands.name AS brand_name')->get();
		}
		else {
			$db_twowayModels = array();
		}
		
		//create twoway devices
		$roomObj->twoway_devices = array();
		foreach($twoway_devices as &$tdevice) {
			$roomObj->twoway_devices[] = $this->createTwowayDevice($tdevice, $db_twowayModels);
		}

		//system twoway devices
		if($this->twoway_sys_devices) {
			foreach($this->twoway_sys_devices as &$tdevice) {
				if($tdevice->room_id == $room->id) {
					continue;
				}
				$roomObj->twoway_devices[] = $this->createTwowayDevice($tdevice, $db_twowayModels);
			}
		}

		//Categories
		//$roomObj->categories = &$this->createCategories();

		return $roomObj;
	}

	protected function &createScheEvents(&$room) {

		$eventsObj = array();

		$dbEvents = DB::table('a_events')->where('room_id', '=', $room->id)->orderBy('order', 'asc')->get();

		$i = 0;
		foreach($dbEvents as $event) {
			
			if($event->hidden) {
				continue;
			}
			
			$imageName = $event->image_name;
			if(strlen($imageName) < 1) {
				$imageName = "OTHER";
			}
			$eventsObj[$i] = (object)array('id' => $event->id, 'text' => $event->display_text, 'image' => $imageName, 'option' => $event->option);
			if($event->hidden_option) {
				$eventsObj[$i]->text_hidden = 1;
			}			
			$i++;
		}

		return $eventsObj;
	}

	protected function &createRoomHeader(&$room) {

		$bstationObj = DB::table('a_bstations')->where('system_id', '=', $this->curSystemId)->
			where('master', '=', 1)->first();
		
		$header = new stdClass;
		$header->version = URCValues::EDITOR_VER;
		$header->comment = '';
		$header->id = $room->id;
		$header->name = $room->name;
		if($bstationObj) {
			$header->bstation_mac = $bstationObj->mac;
		}
		$header->download_key = $this->downloadKey;

		return $header;
	}

	protected function &createTwowayDevice(&$tdevice, &$dbModels) {

		$deviceObj = new stdClass;

		$deviceObj->id = $tdevice->id;

		$deviceObj->model = $tdevice->model;
		$deviceObj->name = $tdevice->name;
		$deviceObj->model_id = $tdevice->model_id;
		
		$deviceObj->target_type = $tdevice->target_type & 0xffff;
		$deviceObj->target_addr = $tdevice->target_addr;

		$foundDevice = null;
		if($this->twowaySysParamMgr->getDevice($tdevice->id, $foundDevice) === true && $foundDevice) {
			$deviceObj->target_info = $foundDevice->target_info;
		}

		$deviceObj->twoway_modules = array();

		foreach($dbModels as &$dbModel) {
			if($dbModel->id != $tdevice->model_id) {
				continue;
			}

			$deviceObj->twoway_modules = json_decode($dbModel->twoway_modules);
			$deviceObj->model = $dbModel->brand_name.'_'.$deviceObj->model;//because of Korean Request
			break;
		}
		$deviceObj->file_name = $deviceObj->model.'.json';
		//ErrorDebug::write(json_encode($deviceObj));

		//parameter converter
		$variables = json_decode($tdevice->variables);
		$varCnt = count($variables);
		for($i = 0; $i < $varCnt; $i++) {
			if(!isset($variables[$i]->name) || !isset($variables[$i]->value)) {
				$varCnt = 0;
				break;
			}
		}
		if($varCnt > 0) {
			foreach($deviceObj->twoway_modules as &$twowayModule) {
				if(!isset($twowayModule->parameter)) {
					continue;
				}
				
				foreach($variables as &$variable) {
					$twowayModule->parameter = str_replace('<<'.$variable->name.'>>', $variable->value, $twowayModule->parameter);
				}
			}
		}

		return $deviceObj;
	}

	protected function &createDevice(&$device, $isMain, &$devices) {

		$deviceObj = new stdClass;

		$deviceObj->id = $device->id;

		$deviceObj->dev_type = $device->dev_type;
		$deviceObj->category = $device->category;
		$deviceObj->name = $device->name;
		//$deviceObj->punch_vol = $device->punch_vol;

		if($deviceObj->dev_type == 1) {//SNP-2

			$deviceObj->model = $device->model;
			$deviceObj->model_id = $device->model_id;
			$deviceObj->punch_vol = $device->punch_vol;//because of Checking volume

			$deviceObj->hard_buttons = array();

			switch($device->target_type)
			{
			case URCValues::DB_TYPE_IR://IR
				$deviceObj->target_type = URCValues::TWPWAY_TYPE_NONE;			
				break;
			case URCValues::DB_TYPE_IP://IP
			case URCValues::DB_TYPE_UDP:
				$deviceObj->target_type = URCValues::TWOWAY_TYPE_IP;
				$deviceObj->target_addr = $device->target_addr.':'.$device->target_port;
				break;
			case URCValues::DB_TYPE_MAC:
				$deviceObj->target_type = URCValues::TWOWAY_TYPE_MAC;
				$deviceObj->target_addr = $device->target_addr;
				break;
			}
		}
		else {

			if($device->fav_option) {
				$deviceObj->fav_option = 1;
			}

			//Keybaord
			$keyData = DB::table('a_keys_db')->select('id', 'name')->
				where('room_id', '=', $this->curRoomId)->
				where('device_id', '=', $device->id)->get();
			if($keyData && count($keyData) > 0) {
				$deviceObj->keyboard = 1;
				$deviceObj->keyData = $keyData;
			}

			$deviceObj->punch_vol = $device->punch_vol;//because of Checking volume

			$deviceObj->hard_buttons = &$this->createHardBtns($device);
			$deviceObj->pages = &$this->createPages($device, $isMain, $devices);
		}

		return $deviceObj;
	}

	protected function &createHardBtns(&$device) {

		$btnsObj = array();

		$dbBtns = DB::table('a_btns')->where('room_id', '=', $this->curRoomId)->
			where('device_id', '=', $device->id)->
			where('page_id', '=' -1)->get();

		$i = 0;
		foreach($dbBtns as $btn) {

			$btnsObj[$i] = (object)array('id' => $btn->id, 'text' => $btn->display_text);
			$i++;
		}
		
		return $btnsObj;
	}

	protected function applyPunchDevice(&$deviceObj, &$devices) {
		
		if($deviceObj->punch_vol < 0) {
			return;
		}

		$punchDevice = null;
		foreach($devices as $device) {
			if($device->id == $deviceObj->punch_vol)
			{
				$punchDevice = $device;
				break;
			}
		}

		if($punchDevice == null) {
			return;
		}

		$arVolKey = array('vol+' => -1, 'vol-' => -1, 'mute' => -1);
		foreach($deviceObj->hard_buttons as $hbtn) {

			switch($hbtn->id)
			{
			case URCValues::UDML_VOL_UP:
				$arVolKey['vol+'] = $hbtn->id;
				break;
			case URCValues::UDML_VOL_DN:
				$arVolKey['vol-'] = $hbtn->id;
				break;
			case URCValues::UDML_MUTE:
				$arVolKey['mute'] = $hbtn->id;
				break;
			}
		}

		if($arVolKey['vol+'] < 0 || $arVolKey['vol-'] < 0 || $arVolKey['mute'] < 0) {

			foreach($punchDevice->hard_buttons as $hbtn) {

				switch($hbtn->id) {
				case URCValues::UDML_VOL_UP:
					if($arVolKey['vol+'] < 0) {
						$deviceObj->hard_buttons[] = (object)array('id' => URCValues::UDML_VOL_UP, 'text' => $hbtn->text);
					}
					break;
				case URCValues::UDML_VOL_DN:
					if($arVolKey['vol-'] < 0) {
						$deviceObj->hard_buttons[] = (object)array('id' => URCValues::UDML_VOL_DN, 'text' => $hbtn->text);						
					}
					break;
				case URCValues::UDML_MUTE:
					if($arVolKey['mute'] < 0) {
						$deviceObj->hard_buttons[] = (object)array('id' => URCValues::UDML_MUTE, 'text' => $hbtn->text);
					}
					break;
				}
			}
		}
	}

	protected function initCalcPage() {

		$this->calcPageId = -1;
		$this->calcPageObj = null;
	}

	protected function &getCalcPage(&$pagesObj, $pageId) {

		if($this->calcPageId != $pageId) {

			$newPageObj = new stdClass;
			$newPageObj->buttons = array();
			//$newPageObj->id = $pageId;

			$len = count($pagesObj);
			$pagesObj[$len] = $newPageObj;

			$this->calcPageObj = $newPageObj;
			$this->calcPageId = $pageId;
		}

		return $this->calcPageObj;
	}

	protected function &createPages(&$device, $isMain, &$devices) {

		$pagesObj = array();

		$dbBtns = DB::table('a_btns')->where('room_id', '=', $this->curRoomId)->
			where('device_id', '=', $device->id)->
			whereNotIn('page_id', array(-1))->orderBy('page_id', 'asc')->orderBy('page_btn_idx', 'asc')->get();
	
		$this->initCalcPage();

		if($isMain) {

			$pageObj = &$this->getCalcPage($pagesObj, 0);
				
			$idxBtn = 0;
			foreach($dbBtns as $btn) {
			
				if($btn->hidden) {
					//$pageObj->buttons[] = (object)array('id' => $btn->id, 'idx' => $btn->page_btn_idx, 'text' => $btn->display_text, 'hidden' => 1);
					continue;
				}
				
				$category = '';
				if($btn->link_id >= 0) {
					foreach($devices as $dbDevice) {
						if($dbDevice->id === $btn->link_id) {
							$category = $dbDevice->category;
							break;
						}
					}
				}

				$imageName = $btn->image_name;
				if(strlen($imageName) < 1) {
					$imageName = "OTHER";
				}

				$pageBtn = array('id' => $btn->id, 'idx' => $idxBtn, 'text' => $btn->display_text, 'image' => $imageName, 'category' => $category);
				
				if($btn->hidden_option) {
					$pageBtn['text_hidden'] = 1;
				}
				$pageObj->buttons[] = (object)$pageBtn;

				$idxBtn++;
			}
		}
		else {

			foreach($dbBtns as $btn) {
				
				$pageObj = &$this->getCalcPage($pagesObj, $btn->page_id);
				
				/*
				if($isMain) {

					if($btn->hidden) {
						//$pageObj->buttons[] = (object)array('id' => $btn->id, 'idx' => $btn->page_btn_idx, 'text' => $btn->display_text, 'hidden' => 1);
						continue;
					}
					
					$category = '';
					if($btn->link_id >= 0) {
						foreach($devices as $dbDevice) {
							if($dbDevice->id === $btn->link_id) {
								$category = $dbDevice->category;
								break;
							}
						}
					}

					$imageName = $btn->image_name;
					if(strlen($imageName) < 1) {
						$imageName = "OTHER";
					}

					$pageBtn = array('id' => $btn->id, 'idx' => $btn->page_btn_idx, 'text' => $btn->display_text, 'image' => $imageName, 'category' => $category);
					
					if($btn->hidden_option) {
						$pageBtn['text_hidden'] = 1;
					}
					$pageObj->buttons[] = (object)$pageBtn;
				}
				else {
				*/
					$pageBtn = array('id' => $btn->id, 'idx' => $btn->page_btn_idx, 'text' => $btn->display_text);
					if($btn->hidden_option) {
						$pageBtn['text_hidden'] = 1;
					}
					if($btn->hidden) {
						$pageBtn['hidden'] = 1;
					}
					$pageObj->buttons[] = (object)$pageBtn;
					
					if($btn->page_hidden) {
					
						if(!isset($pageObj->hidden)) {
							$pageObj->hidden = 1;
						}
					}
					else {
						
						if(isset($pageObj->hidden)) {
							$pageObj->hidden = 0;
						}
					}
				//}
			}
		}
		
		return $pagesObj;
	}

	/*
	protected function &createCategories() {
		
		$categories = array();

		$categories[0] = new stdClass;
		$categories[0]->id = -1;
		$categories[0]->name = 'UNKNOWN';

		$categories[1] = new stdClass;
		$categories[1]->id = 0;
		$categories[1]->name = 'MAIN';

		return $categories;
	}
	*/
}

class BStationDataGenerator {

	var $downloadKey = null;
	var $systemId = -1;
	var $userId = -1;
	var $curRoomId = -1;
	var $roomDevices = array();
	var $twowaySysParamMgr = null;

	function __construct($userId, $systemId, $downloadKey, &$twowaySysParamMgr) {		
		$this->userId = $userId;
		$this->systemId = $systemId;
		$this->downloadKey = $downloadKey;
		$this->twowaySysParamMgr = $twowaySysParamMgr;
	}

	public function save($filePath) {

		$result = null;
		if($this->generate($result) == false) {
			return false;
		}

		$file = fopen($filePath,"w");
		if($file == false) {
			return false;
		}
		  		
		$jsonData = json_encode($result);
		fputs ($file, $jsonData);

  		fclose ($file);

  		return true;
	}

	public function saveToDB() {

		$result = null;
		if($this->generate($result) == false) {
			return false;
		}

		$jsonData = json_encode($result);

		//ErrorDebug::write('saveToDB');
		//ErrorDebug::write($jsonData);
		
		$downData = DB::table('a_download')->where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_BSTATION)->
			where('system_id', '=', $this->systemId)->get();

		if($downData && count($downData) != 1)
		{
			DB::table('a_download')->where('id', '=', $this->userId)->
			where('type', '=', URCValues::DOWN_TYPE_BSTATION)->
			where('system_id', '=', $this->systemId)->delete();

			$downData = null;
		}

		$crc = crc32($jsonData);
		$crc_string = sprintf('%u', $crc);

		if($downData) {
			DB::table('a_download')->where('id', '=', $this->userId)->
				where('type', '=', URCValues::DOWN_TYPE_BSTATION)->
				where('system_id', '=', $this->systemId)->update(array('data' => $jsonData, 'crc' => $crc_string));
		}
		else {
			DB::table('a_download')->insert(array('id' => $this->userId, 'type' => URCValues::DOWN_TYPE_BSTATION,
				'system_id' => $this->systemId, 'data' => $jsonData, 'crc' => $crc_string));
		}

		return true;
	}

	public function generate(&$systemObj) {
		
		$system = DB::table('a_systems')->where('id', '=', $this->systemId)->
			where('user_id', '=', $this->userId)->first();
		if(!$system)
			return false;

		$systemObj = new stdClass;
		
		$systemObj->header = &$this->createHeader();
		if(!$systemObj->header)
			return false;

		$rooms = $this->twowaySysParamMgr->getRooms();

		$lenRoom = 0;
		if($rooms) $lenRoom = count($rooms);
		
		$systemObj->rooms = array();
		for($i = 0; $i < $lenRoom; $i++) {
			$systemObj->rooms[$i] = &$this->createRoom($rooms[$i]);
		}

		return true;
	}

	protected function setCurRoomId($roomId) {

		$this->curRoomId = $roomId;
	}

	protected function &createHeader() {

		$system = DB::table('a_systems')->where('id', '=', $this->systemId)->
			where('user_id', '=', $this->userId)->first();
		if(!$system)
			return null;

		$bstationObj = DB::table('a_bstations')->where('system_id', '=', $this->systemId)->
			where('master', '=', 1)->first();
		if(!$bstationObj)
			return null;

		$header = new stdClass;
		$header->version = URCValues::EDITOR_VER;
		$header->comment = '';
		$header->id = $bstationObj->system_id;
		$header->name = $system->name;
		$header->download_key = $this->downloadKey;

		//store master information in the header
		$header->bstation_mac = $bstationObj->mac;

		//timezone
		if($system->timezone_id >= 0) {
			$timezone = DB::table('timezone')->where('id', '=', $system->timezone_id)->first();
			if($timezone) {
				$header->timezone = new stdClass;
				//$header->timezone->name = $timezone->name;
				$header->timezone->bias = $timezone->bias;
				//$header->timezone->s_name = $timezone->s_name;
				$header->timezone->s_time = $timezone->s_time;
				$header->timezone->s_bias = $timezone->s_bias;
				//$header->timezone->d_name = $timezone->d_name;
				$header->timezone->d_time = $timezone->d_time;
				$header->timezone->d_bias = $timezone->d_bias;

				$header->timezone->dst_auto = $system->timezone_dst;
			}
		}
		$header->time_type = $system->time_type;

		//bstations
		$bstations = DB::table('a_bstations')->where('system_id', '=', $this->systemId)->get();
		foreach($bstations as $bstation) {
			unset($bstation->id);
			unset($bstation->system_id);
			unset($bstation->room_id);
		}		
		$header->bstations = $bstations;

		//remotes
		$remotes = DB::table('a_remotes')->where('system_id', '=', $this->systemId)->get();
		foreach($remotes as $remote) {
			unset($remote->id);
			unset($remote->system_id);
			unset($remote->room_id);
		}
		$header->remotes = $remotes;

		//variables
		$vars = DB::table('a_variables')->where('system_id', '=', $this->systemId)->orderBy('name', 'asc')->get();
		foreach($vars as $var) {
			unset($var->system_id);
		}
		$header->variables = $vars;

		return $header;
	}

	protected function &createRoom(&$room) {

		$roomObj = new stdClass;

		$roomObj->name = $room->name;
		$roomObj->id = $room->id;
		/*
		$roomObj->bstation_mac = $room->bstation;
		$roomObj->master = $room->master;
		if($room->remote && strlen($room->remote) >= 12) {
			$roomObj->remote_mac = $room->remote;
		}
		else {
			$roomObj->remote_mac = $room->remote;
		}
		
		$roomObj->light_level = $room->light_level;
		*/

		$this->setCurRoomId($room->id);
		
		//$devices = DB::table('a_devices')->where('room_id', '=', $room->id)->
		//	whereNotIn('id', array($room->main_device_id))->get();//not needed system(please delete system_id in the a_devices)
		$this->roomDevices = DB::table('a_devices')->where('room_id', '=', $room->id)->get();//$rooms[$i]->main_device_id
	
		$roomObj->sys_buttons = array();
		$roomObj->sys_buttons[] = &$this->createSysButton();
		
		//devices
		$roomObj->devices = array();
		foreach($this->roomDevices as $device) {
			$roomObj->devices[] = &$this->createDevice($device);
		}


		//room twoway devices
		$twoway_devices = DB::table('a_twoway_devices')->where('room_id', '=', $room->id)->get();

		$db_twowayDevIdsAll = array();
		foreach($twoway_devices as &$tdevice) {
			$db_twowayDevIdsAll[] = $tdevice->model_id;
		}
		$db_twowayDevIds = array_unique($db_twowayDevIdsAll);

		if(count($db_twowayDevIds) > 0) {
			//$db_twowayModels = DB::table('a_db2_models')->whereIn('id', $db_twowayDevIds)->get();

			$db_twowayModels = DB::table('a_db2_models')->join('a_db2_brands', function($join)
			{
				$join->on('a_db2_models.brand_id', '=', 'a_db2_brands.id');
			})->whereIn('a_db2_models.id', $db_twowayDevIds)->
			select('a_db2_models.id', 'a_db2_brands.name AS brand_name')->get();
		}
		else {
			$db_twowayModels = array();
		}

		//create twoway devices
		$roomObj->twoway_devices = array();
		foreach($twoway_devices as &$tdevice) {

			$twoway_real_name = '';
			foreach($db_twowayModels as &$dbModel) {
				if($dbModel->id != $tdevice->model_id) {
					continue;
				}
				$twoway_real_name = $dbModel->brand_name.'_'.$tdevice->model;
				break;
			}
			if(strlen($twoway_real_name) > 0) {
				$roomObj->twoway_devices[] = $this->createTwowayDevice($tdevice, $twoway_real_name);
			}
		}

		//schedule event
		$roomObj->schedule_event = &$this->createScheEvents($room);
		
		//external services		
		$roomObj->ext_services = array();

		$amazonObj = new URCAmazonData($this->systemId);
		$amazoneService = $amazonObj->getServiceObj();
		if($amazoneService) {
		
			$amazonScenes = array();
			$infoBase64 = '';
			$amazonObj->getScenesAndInfo($room->id, $amazonScenes, $infoBase64);
			//ErrorDebug::write('param');
			//ErrorDebug::write($infoBase64);
			foreach($amazonScenes as $scene) {
				$scene->macro = json_decode($scene->macro);
			}		
			$amazoneService->scenes = $amazonScenes;
			$amazoneService->params = $infoBase64;

			$roomObj->ext_services[] = $amazoneService;
		}

		return $roomObj;
	}

	protected function &createTwowayDevice(&$device, $twoway_real_name) {
		unset($device->room_id);
		unset($device->data);

		$foundDevice = null;
		if($this->twowaySysParamMgr->getDevice($device->id, $foundDevice) === true && $foundDevice) {
		
			$device->script = $foundDevice->script;
			$device->parameter = $foundDevice->parameter;
			$device->target_info = $foundDevice->target_info;
		}	
		unset($device->variables);

		$device->target_type = $device->target_type & 0xffff;
		$device->extra_info = json_decode($device->extra_info);
		$device->model = $twoway_real_name;
		$device->file_name = $device->model.'.json';

		$btnObj = new stdClass;
		if($device->auto_wait) $btnObj->auto_wait = URCValues::AUTO_WAIT_ON;
		$btnObj->power_page_option = $device->popup;
		if($device->popup != URCValues::POPUP_OFF) {
			$btnObj->power_page = json_decode($device->activity);
			$this->checkActivity($btnObj->power_page);			
		}

		if($device->edit_type == URCValues::ETYPE_MACRO) {
			$btnObj->macro = json_decode($device->macro);
		}

		unset($device->auto_wait);
		unset($device->edit_type);
		unset($device->popup);
		unset($device->activity);
		unset($device->macro);

		$device->button = $btnObj;

		//ErrorDebug::write($device->file_name);
		
		return $device;
	}

	protected function &createScheEvents(&$room) {

		$eventsObj = array();

		$dbEvents = DB::table('a_events')->where('room_id', '=', $room->id)->orderBy('order', 'asc')->get();

		$i = 0;
		foreach($dbEvents as $event) {
			
			$eventsObj[$i] = (object)array('id' => $event->id, 'default_state' => $event->default_state, 
				'option' => $event->option, 'day_week' => $event->day_week, 'time' => $event->time, 'macro' => $event->macro);
			$i++;
		}

		return $eventsObj;
	}

	protected function checkActivity(&$activity) {
		
		if(!$this->roomDevices) {
			return;
		}
		
		$count = count($activity);

		for($i = 0; $i < $count; $i++) {
			$chkId = $activity[$i]->device_id;
			foreach($this->roomDevices as $roomDevice) {
				if($chkId == $roomDevice->id) {
					$chkId = -1;
					break;
				}
			}

			if($chkId >= 0) {
				array_splice($activity, $i, 1);
				$i--;
				$count--;
				//ErrorDebug::write('unsetWork'.$chkStr);
			}
			else if(isset($activity[$i]->navigate)) {//Input

				if($activity[$i]->type !== 2 || $activity[$i]->navigate === 0) {
					unset($activity[$i]->navigate);
				}
			}
		}
	}

	protected function &createSysButton() {

		$sysBtnObj = new stdClass;
		
		$sysBtn = DB::table('a_btns')->where('room_id', '=', $this->curRoomId)->
			where('id', '=', URCValues::UDML_SYS_OFF)->first();

		if(!$sysBtn) {
			return $sysBtnObj;
		}

		$sysBtnObj->id = $sysBtn->id;
		if($sysBtn->auto_wait) $sysBtnObj->auto_wait = URCValues::AUTO_WAIT_ON;
		$sysBtnObj->system_off_page = json_decode($sysBtn->activity);
		$this->checkActivity($sysBtnObj->system_off_page);
		
		if($sysBtn->edit_type == URCValues::ETYPE_MACRO) {
			$sysBtnObj->macro = json_decode($sysBtn->macro);
		}

		return $sysBtnObj;
	}

	protected function &createConDBData(&$device) {

		$dbData = DB::table('a_con_db')->where('room_id', '=', $this->curRoomId)->
			where('device_id', '=', $device->id)->get();

		foreach($dbData as &$dbFunc) {
			unset($dbFunc->device_id);
			unset($dbFunc->room_id);

			if($dbFunc->custom !== 1) {
				unset($dbFunc->press_hold);
				unset($dbFunc->repeat_min);
				unset($dbFunc->repeat_macro);
			}
			unset($dbFunc->custom);
		}

		return $dbData;
	}

	protected function &createKeyDBData(&$device) {

		$dbData = DB::table('a_keys_db')->where('room_id', '=', $this->curRoomId)->
			where('device_id', '=', $device->id)->get();

		foreach($dbData as &$dbFunc) {
			unset($dbFunc->device_id);
			unset($dbFunc->room_id);

			if($dbFunc->custom !== 1) {
				unset($dbFunc->press_hold);
				unset($dbFunc->repeat_min);
				unset($dbFunc->repeat_macro);
			}
			unset($dbFunc->custom);
		}

		return $dbData;
	}

	protected function &createButton(&$btn) {

		$btnObj = new stdClass;

		$btnObj->id = $btn->id;
		if($btn->auto_wait) $btnObj->auto_wait = URCValues::AUTO_WAIT_ON;
		$btnObj->power_page_option = $btn->popup;
		if($btn->popup != URCValues::POPUP_OFF) {
			$btnObj->power_page = json_decode($btn->activity);
			$this->checkActivity($btnObj->power_page);			
		}

		if($btn->edit_type == URCValues::ETYPE_MACRO) {
			$btnObj->macro = json_decode($btn->macro);
		}

		if($btn->link_id >= 0) {
			$btnObj->link_id = $btn->link_id;
		}

		//if($btn->edit_type == URCValues::ETYPE_ACTIVITY) {
		//	$btnObj->macro = json_decode($btn->macro);
		//}
		//else {
		//	$btnObj->macro = $btn->macro;
		//}

		return $btnObj;
	}

	protected function &createButtons(&$device) {

		$btnsObj = array();

		$dbBtns = DB::table('a_btns')->where('room_id', '=', $this->curRoomId)->
			where('device_id', '=', $device->id)->get();

		foreach($dbBtns as $btn) {

			$btnsObj[] = &$this->createButton($btn);
		}
		
		return $btnsObj;
	}

	protected function &createDevice(&$device) {

		$deviceObj = new stdClass;

		$deviceObj->id = $device->id;

		$deviceObj->dev_type = $device->dev_type;

		if($deviceObj->dev_type == 1) {//SNP-2
			$deviceObj->model = $device->model;
			$deviceObj->model_id = $device->model_id;
		}
		
		$deviceObj->category = $device->category;
		$deviceObj->name = $device->name;
		$deviceObj->punch_vol = $device->punch_vol;

		$deviceObj->target = new stdClass;
		$deviceObj->target->type = $device->target_type;
		switch($deviceObj->target->type)
		{
		case URCValues::DB_TYPE_IR://IR
			$deviceObj->target->bstation_mac = $device->target_addr;
			$deviceObj->target->ir_port = $device->target_port;
			break;
		case URCValues::DB_TYPE_IP://IP
		case URCValues::DB_TYPE_UDP:
			$deviceObj->target->ip = $device->target_addr;
			$deviceObj->target->port = $device->target_port;

			$deviceObj->ramp = new stdClass;
			$deviceObj->ramp->start = $device->ramp_start;
			$deviceObj->ramp->speed = $device->ramp_speed;
			
			$deviceObj->attr = new stdClass;
			$deviceObj->attr->auto_cr = $device->auto_cr;
			$deviceObj->attr->con_time = $device->con_time;
			$deviceObj->attr->delay_after_send = $device->delay_after_send;
			break;
		case URCValues::DB_TYPE_MAC:
			$deviceObj->target->mac = $device->target_addr;

			if($deviceObj->dev_type == 1) {//SNP-2

				$deviceObj->target->model_id = URCValues::getModelProvId($deviceObj->model);
					
				switch($deviceObj->model) {
				case "SNP-2" :
					$deviceObj->target->com_type = "udp";
					$deviceObj->target->port = 57002;
					break;
				}
			}

			$deviceObj->ramp = new stdClass;
			$deviceObj->ramp->start = $device->ramp_start;
			$deviceObj->ramp->speed = $device->ramp_speed;
			
			$deviceObj->attr = new stdClass;
			$deviceObj->attr->auto_cr = $device->auto_cr;
			$deviceObj->attr->con_time = $device->con_time;
			$deviceObj->attr->delay_after_send = $device->delay_after_send;

			;
			break;
		}
		
		//if($deviceObj->dev_type == 0) {//NOT SNP-2
		
			$deviceObj->fav_option = new stdClass;
			$deviceObj->fav_option->enable = $device->fav_option;
			$deviceObj->fav_option->delay = $device->fav_delay;
			$deviceObj->fav_option->enter = $device->fav_enter;
		//}
						
		$deviceObj->repeat = new stdClass;
		$deviceObj->repeat->min = $device->repeat_min;
		$deviceObj->repeat->macro = $device->repeat_macro;

		$deviceObj->db_data = &$this->createConDBData($device);
		$deviceObj->db_keys = &$this->createKeyDBData($device);
		$deviceObj->buttons = &$this->createButtons($device);

		return $deviceObj;
	}

}
