/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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
 * of the License, 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL

#include "common/scummsys.h"

#ifdef MACOSX

#include "backends/audiocd/macosx/macosx-audiocd.h"
#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
#include "backends/platform/sdl/macosx/appmenu_osx.h"
#include "backends/platform/sdl/macosx/macosx.h"
#include "backends/updates/macosx/macosx-updates.h"
#include "backends/taskbar/macosx/macosx-taskbar.h"
#include "backends/platform/sdl/macosx/macosx_wrapper.h"

#include "common/archive.h"
#include "common/config-manager.h"
#include "common/fs.h"
#include "common/translation.h"

#include "ApplicationServices/ApplicationServices.h"	// for LSOpenFSRef
#include "CoreFoundation/CoreFoundation.h"	// for CF* stuff

OSystem_MacOSX::OSystem_MacOSX()
	:
	OSystem_POSIX("Library/Preferences/ResidualVM Preferences") {
}

void OSystem_MacOSX::init() {
	// Use an iconless window on OS X, as we use a nicer external icon there.
	_window = new SdlIconlessWindow();

#if defined(USE_TASKBAR)
	// Initialize taskbar manager
	_taskbarManager = new MacOSXTaskbarManager();
#endif

	// Invoke parent implementation of this method
	OSystem_POSIX::init();
}

void OSystem_MacOSX::initBackend() {
	// Create the mixer manager
	if (_mixer == 0) {
		_mixerManager = new DoubleBufferSDLMixerManager();

		// Setup and start mixer
		_mixerManager->init();
	}

#ifdef USE_TRANSLATION
	// We need to initialize the translataion manager here for the following
	// call to replaceApplicationMenuItems() work correctly
	TransMan.setLanguage(ConfMan.get("gui_language").c_str());
#endif // USE_TRANSLATION

	// Replace the SDL generated menu items with our own translated ones on Mac OS X
	replaceApplicationMenuItems();

#ifdef USE_SPARKLE
	// Initialize updates manager
	_updateManager = new MacOSXUpdateManager();
#endif

	// Invoke parent implementation of this method
	OSystem_POSIX::initBackend();
}

void OSystem_MacOSX::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
	// Invoke parent implementation of this method
	OSystem_POSIX::addSysArchivesToSearchSet(s, priority);

	// Get URL of the Resource directory of the .app bundle
	CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
	if (fileUrl) {
		// Try to convert the URL to an absolute path
		UInt8 buf[MAXPATHLEN];
		if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) {
			// Success: Add it to the search path
			Common::String bundlePath((const char *)buf);
			s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority);
		}
		CFRelease(fileUrl);
	}
}

bool OSystem_MacOSX::hasFeature(Feature f) {
	if (f == kFeatureDisplayLogFile || f == kFeatureClipboardSupport || f == kFeatureOpenUrl)
		return true;
	return OSystem_POSIX::hasFeature(f);
}

bool OSystem_MacOSX::displayLogFile() {
	// Use LaunchServices to open the log file, if possible.

	if (_logFilePath.empty())
		return false;

    CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)_logFilePath.c_str(), _logFilePath.size(), false);
    OSStatus err = LSOpenCFURLRef(url, NULL);
    CFRelease(url);

	return err != noErr;
}

bool OSystem_MacOSX::hasTextInClipboard() {
	return hasTextInClipboardMacOSX();
}

Common::String OSystem_MacOSX::getTextFromClipboard() {
	return getTextFromClipboardMacOSX();
}

bool OSystem_MacOSX::openUrl(const Common::String &url) {
	CFURLRef urlRef = CFURLCreateWithBytes (NULL, (UInt8*)url.c_str(), url.size(), kCFStringEncodingASCII, NULL);
	OSStatus err = LSOpenCFURLRef(urlRef, NULL);
	CFRelease(urlRef);
	return err == noErr;
}

Common::String OSystem_MacOSX::getSystemLanguage() const {
#if defined(USE_DETECTLANG) && defined(USE_TRANSLATION)
	CFArrayRef availableLocalizations = CFBundleCopyBundleLocalizations(CFBundleGetMainBundle());
	if (availableLocalizations) {
		CFArrayRef preferredLocalizations = CFBundleCopyPreferredLocalizationsFromArray(availableLocalizations);
		CFRelease(availableLocalizations);
		if (preferredLocalizations) {
			CFIndex localizationsSize = CFArrayGetCount(preferredLocalizations);
			// Since we have a list of sorted preferred localization, I would like here to
			// check that they are supported by the TranslationManager and take the first
			// one that is supported. The listed localizations are taken from the Bundle
			// plist file, so they should all be supported, unless the plist file is not
			// synchronized with the translations.dat file. So this is not really a big
			// issue. And because getSystemLanguage() is called from the constructor of
			// TranslationManager (therefore before the instance pointer is set), calling
			// TransMan here results in an infinite loop and creation of a lot of TransMan
			// instances.
			/*
			for (CFIndex i = 0 ; i < localizationsSize ; ++i) {
				CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(preferredLocalizations, i);
				char buffer[10];
				CFStringGetCString(language, buffer, sizeof(buffer), kCFStringEncodingASCII);
				int32 languageId = TransMan.findMatchingLanguage(buffer);
				if (languageId != -1) {
					CFRelease(preferredLocalizations);
					return TransMan.getLangById(languageId);
				}
			}
			*/
			if (localizationsSize > 0) {
				CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(preferredLocalizations, 0);
				char buffer[10];
				CFStringGetCString(language, buffer, sizeof(buffer), kCFStringEncodingASCII);
				CFRelease(preferredLocalizations);
				return buffer;
			}
			CFRelease(preferredLocalizations);
		}

	}
	// Falback to POSIX implementation
	return OSystem_POSIX::getSystemLanguage();
#else // USE_DETECTLANG
	return OSystem_POSIX::getSystemLanguage();
#endif // USE_DETECTLANG
}

Common::String OSystem_MacOSX::getScreenshotsPath() {
	Common::String path = ConfMan.get("screenshotpath");
	if (path.empty())
		path = getDesktopPathMacOSX();
	if (!path.empty() && !path.hasSuffix("/"))
		path += "/";
	return path;
}

AudioCDManager *OSystem_MacOSX::createAudioCDManager() {
	return createMacOSXAudioCDManager();
}

#endif
