/*
* Copyright (C) 2005-2009 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC Remote; see the file license. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
package org.xbmc.android.util;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xbmc.api.business.INotifiableManager;
import org.xbmc.api.data.IControlClient;
import org.xbmc.api.data.IEventClient;
import org.xbmc.api.data.IInfoClient;
import org.xbmc.api.data.IMusicClient;
import org.xbmc.api.data.ITvShowClient;
import org.xbmc.api.data.IVideoClient;
import org.xbmc.api.info.SystemInfo;
import org.xbmc.api.object.Host;
import org.xbmc.eventclient.EventClient;
import org.xbmc.jsonrpc.JsonRpc;
import org.xbmc.httpapi.HttpApi;
import org.xbmc.httpapi.WifiStateException;
import android.content.Context;
import android.util.Log;
public abstract class ClientFactory {
public static int XBMC_REV = -1;
public static final int MIN_JSONRPC_REV = 27770;
public static final int MICROHTTPD_REV = 27770;
public static final int THUMB_TO_VFS_REV = 29743;
public static final int API_TYPE_UNSET = 0;
public static final int API_TYPE_HTTPIAPI = 1;
public static final int API_TYPE_JSONRPC = 2;
private static HttpApi sHttpClient;
private static JsonRpc sJsonClient;
private static EventClient sEventClient;
private static int sApiType = API_TYPE_JSONRPC;
private static final String TAG = "ClientFactory";
private static final String NAME = "Android XBMC Remote";
public static IInfoClient getInfoClient(INotifiableManager manager, Context context) throws WifiStateException {
assertWifiState(context);
probeQueryApiType(manager);
switch (sApiType) {
case API_TYPE_JSONRPC:
return createJsonClient(manager).info;
case API_TYPE_UNSET:
case API_TYPE_HTTPIAPI:
default:
return createHttpClient(manager).info;
}
}
public static IControlClient getControlClient(INotifiableManager manager, Context context) throws WifiStateException {
assertWifiState(context);
probeQueryApiType(manager);
switch (sApiType) {
case API_TYPE_JSONRPC:
return createJsonClient(manager).control;
case API_TYPE_UNSET:
case API_TYPE_HTTPIAPI:
default:
return createHttpClient(manager).control;
}
}
public static IVideoClient getVideoClient(INotifiableManager manager, Context context) throws WifiStateException {
assertWifiState(context);
probeQueryApiType(manager);
switch (sApiType) {
case API_TYPE_JSONRPC:
return createJsonClient(manager).video;
case API_TYPE_UNSET:
case API_TYPE_HTTPIAPI:
default:
return createHttpClient(manager).video;
}
}
public static IMusicClient getMusicClient(INotifiableManager manager, Context context) throws WifiStateException {
assertWifiState(context);
probeQueryApiType(manager);
switch (sApiType) {
case API_TYPE_JSONRPC:
return createJsonClient(manager).music;
case API_TYPE_UNSET:
case API_TYPE_HTTPIAPI:
default:
return createHttpClient(manager).music;
}
}
public static ITvShowClient getTvShowClient(INotifiableManager manager, Context context) throws WifiStateException {
assertWifiState(context);
probeQueryApiType(manager);
switch (sApiType) {
case API_TYPE_JSONRPC:
return createJsonClient(manager).shows;
case API_TYPE_UNSET:
case API_TYPE_HTTPIAPI:
default:
return createHttpClient(manager).shows;
}
}
private static void assertWifiState(Context context) throws WifiStateException {
if (context != null && HostFactory.host != null && HostFactory.host.wifi_only){
final int state = WifiHelper.getInstance(context).getWifiState();
if (state != WifiHelper.WIFI_STATE_CONNECTED) {
throw new WifiStateException(state);
}
}
}
public static IEventClient getEventClient(INotifiableManager manager) {
return createEventClient(manager);
}
/**
* Resets the client so it has to re-read the settings and recreate the instance.
* @param host New host settings, can be null.
*/
public static void resetClient(Host host) {
//sApiType = API_TYPE_UNSET;
if (sHttpClient != null) {
sHttpClient.setHost(host);
} else if(sJsonClient != null){
sJsonClient.setHost(host);
}else{
Log.w(TAG, "Not updating http client's host because no instance is set yet.");
}
Log.i(TAG, "Resetting client to " + (host == null ? "<nullhost>" : host.addr));
if (sEventClient != null) {
try {
if (host != null) {
InetAddress addr = Inet4Address.getByName(host.addr);
sEventClient.setHost(addr, host.esPort > 0 ? host.esPort : Host.DEFAULT_EVENTSERVER_PORT);
} else {
sEventClient.setHost(null, 0);
}
} catch (UnknownHostException e) {
Log.e(TAG, "Unknown host: " + (host == null ? "<nullhost>" : host.addr));
}
} else {
Log.w(TAG, "Not updating event client's host because no instance is set yet.");
}
}
/**
* Returns an instance of the HTTP Client. Instantiation takes place only
* once, otherwise the first instance is returned.
*
* @param manager Upper layer reference
* @return HTTP client
*/
private static HttpApi createHttpClient(final INotifiableManager manager) {
final Host host = HostFactory.host;
if (sHttpClient == null) {
if (host != null && !host.addr.equals("")){
sHttpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT);
} else {
sHttpClient = new HttpApi(null, -1);
}
// do some init stuff
(new Thread("Init-Connection") {
public void run() {
sHttpClient.control.setResponseFormat(manager);
}
}).start();
}
return sHttpClient;
}
/**
* Returns an instance of the JSON-RPC Client. Instantiation takes place only
* once, otherwise the first instance is returned.
*
* @param manager Upper layer reference
* @return JSON-RPC client
*/
private static JsonRpc createJsonClient(final INotifiableManager manager) {
final Host host = HostFactory.host;
if (sJsonClient == null) {
if (host != null && !host.addr.equals("")){
sJsonClient = new JsonRpc(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT);
} else {
sJsonClient = new JsonRpc(null, -1);
}
}
return sJsonClient;
}
/**
* Tries to find out which xbmc flavor and which API is running.
* @param manager Upper layer reference
*/
private static void probeQueryApiType(final INotifiableManager manager) {
final Host host = HostFactory.host;
if (sApiType != API_TYPE_UNSET) {
return;
}
// try to get version string via http api
final HttpApi httpClient;
if (host != null && !host.addr.equals("")){
httpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT);
} else {
httpClient = new HttpApi(null, -1);
}
final String version = httpClient.info.getSystemInfo(manager, SystemInfo.SYSTEM_BUILD_VERSION);
Log.i(TAG, "VERSION = " + version);
// 1. try to match xbmc's version
Pattern pattern = Pattern.compile("r\\d+");
Matcher matcher = pattern.matcher(version);
if (matcher.find()) {
final int rev = Integer.parseInt(matcher.group().substring(1));
Log.i(TAG, "Found XBMC at revision " + rev + "!");
XBMC_REV = rev;
sApiType = rev >= MIN_JSONRPC_REV ? API_TYPE_JSONRPC : API_TYPE_HTTPIAPI;
} else {
// parse git version
pattern = Pattern.compile("Git.([a-f\\d]+)");
matcher = pattern.matcher(version);
if (matcher.find()) {
final String commit = matcher.group(1);
Log.i(TAG, "Found XBMC at Git commit " + commit + "!");
// set to last revision where we used SVN
XBMC_REV = 35744;
sApiType = API_TYPE_JSONRPC;
}
// 2. try to match boxee's version
// 3. plex? duh.
//sApiType = API_TYPE_UNSET;
}
}
/**
* Returns an instance of the Event Server Client. Instantiation takes
* place only once, otherwise the first instance is returned.
*
* @param manager Upper layer reference
* @return Client for XBMC's Event Server
*/
private static IEventClient createEventClient(final INotifiableManager manager) {
if (sEventClient == null) {
final Host host = HostFactory.host;
if (host != null) {
try {
final InetAddress addr = Inet4Address.getByName(host.addr);
sEventClient = new EventClient(addr, host.esPort > 0 ? host.esPort : Host.DEFAULT_EVENTSERVER_PORT, NAME);
Log.i(TAG, "EventClient created on " + addr);
} catch (UnknownHostException e) {
manager.onMessage("EventClient: Cannot parse address \"" + host.addr + "\".");
Log.e(TAG, "EventClient: Cannot parse address \"" + host.addr + "\".");
sEventClient = new EventClient(NAME);
}
} else {
manager.onMessage("EventClient: Failed to read host settings.");
Log.e(TAG, "EventClient: Failed to read host settings.");
sEventClient = new EventClient(NAME);
}
}
return sEventClient;
}
}