
#include <Spectre/System/Log.h>
#include <Platform/PlatformMisc.h>
#include "Xlib.h"
#include <X11/extensions/Xrandr.h>
#include <algorithm>

namespace sp {

// Code "borrowed" from SFML :)
// see: https://github.com/SFML/SFML/blob/master/src/SFML/Window/Unix/VideoModeImpl.cpp

void PlatformMisc::GetDisplayModes(std::vector<DisplayMode>& modes)
{
	::Display *disp = Xlib::getDisplay();

	if (disp) {
		int scr = DefaultScreen(disp);

		// Check for XRandR.
		int ver;
		if (XQueryExtension(disp, "RANDR", &ver, &ver, &ver)) {

			XRRScreenConfiguration* config = ::XRRGetScreenInfo(disp, RootWindow(disp, scr));
			if (config) {
				int nbSizes;
				XRRScreenSize* sizes = ::XRRConfigSizes(config, &nbSizes);
				if (sizes && nbSizes > 0) {
					int nbDepths = 0;
					int* depths = ::XListDepths(disp, scr, &nbDepths);
					if (depths && nbDepths > 0) {

						for(int i = 0; i < nbDepths; i++) {
							for(int j = 0; j < nbSizes; j++) {
								DisplayMode mode(sizes[j].width, sizes[j].height, depths[i]);

								::Rotation rot;
								XRRConfigRotations(config, &rot);

								if (rot == RR_Rotate_90 || rot == RR_Rotate_270) {
									std::swap(mode.width, mode.height);
								}

								if (std::find(modes.begin(), modes.end(), mode) == modes.end()) {
									modes.push_back(mode);
								}
							}
						}

						XFree(depths);
					}
				}
			} else {
				Log::error("Failed to get screen configuration while trying to get display modes.");
			}

			XRRFreeScreenConfigInfo(config);
		} else {
			Log::error("Failed to use XRandR extension while trying to get display modes.");
		}
	} else {
		Log::error("Failed to connect to the X server while trying to get display modes.");
	}
}

DisplayMode PlatformMisc::GetDesktopMode()
{
	DisplayMode mode;

	::Display *disp = Xlib::getDisplay();

	if (disp) {
		int scr = DefaultScreen(disp);

		// Check for XRandR.
		int ver;
		if (XQueryExtension(disp, "RANDR", &ver, &ver, &ver)) {

			XRRScreenConfiguration* config = ::XRRGetScreenInfo(disp, RootWindow(disp, scr));
			if (config) {
				int nbSizes;
				::Rotation rot;
				int current = XRRConfigCurrentConfiguration(config, &rot);

				XRRScreenSize* sizes = ::XRRConfigSizes(config, &nbSizes);
				if (sizes && nbSizes > 0) {

					mode = DisplayMode(sizes[current].width, sizes[current].height, DefaultDepth(disp, scr));

					XRRConfigRotations(config, &rot);
					if (rot == RR_Rotate_90 || rot == RR_Rotate_270) {
						std::swap(mode.width, mode.height);
					}
				}
			} else {
				Log::error("Failed to get screen configuration while trying to get desktop display mode.");
			}

			XRRFreeScreenConfigInfo(config);
		} else {
			Log::error("Failed to use XRandR extension while trying to get desktop display mode.");
		}
	} else {
		Log::error("Failed to connect to the X server while trying to get desktop display mode.");
	}

	return mode;
}

} // namespace sp
