 # -*- coding: utf-8 -*-

import os, sys, time

from PyQt5.QtCore import Qt, QEvent, QThread, pyqtSignal, QRect, QRectF, QTimer, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QLabel
from PyQt5.QtGui import QIcon, QPixmap, QPainter

def get_documents_path():
	if sys.platform == 'win32':
		import ctypes.wintypes
		buff = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
		ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PERSONAL, None, SHGFP_TYPE_CURRENT, buf)
		return os.path.join(buf.value, 'My Games')
	else:
		return os.path.expanduser('~/Documents')

def get_pipe_path(mode='journal'):
	if sys.platform == 'win32':
		return '\\\\.\\pipe\\oneshot-journal-to-game'
	else:
		if mode == 'niko':
			return os.path.expanduser('~/.oneshot-niko-pipe')
		return os.path.expanduser('~/.oneshot-pipe')

left_close = False
if sys.platform == 'darwin': left_close = True

try: base_path = sys._MEIPASS
except AttributeError:
    if os.path.exists(os.getenv('HOME') + "/.cache/sunshine-path.cache"):
        with open(os.getenv('HOME') + "/.cache/sunshine-path.cache", "r", encoding="utf-8") as f:
          for i, line in enumerate(f):
            if i == 1:
              base_path = line.strip()
              break
    else:
        base_path = os.path.abspath('.')

class PipeThread(QThread):
	def __init__(self, *args, **kwargs):
		self.pipe = kwargs['pipe']
		del kwargs['pipe']
		super().__init__(*args, **kwargs)

class WatchPipe(PipeThread):
	change_image = pyqtSignal(str)

	def run(self):
		while True:
			self.change_image.emit('default_en')
			while not os.path.exists(self.pipe): time.sleep(0.1)

			pipe = open(self.pipe, 'r')
			pipe.flush()

			was_nondefault = False

			while os.path.exists(self.pipe): # Make sure the file still exists and wasn't cleaned up by SyngleChance
				message = os.read(pipe.fileno(), 256)
				if len(message) > 0:
					m = message.decode()
					if m != 'default_en':
						was_nondefault = True
					self.change_image.emit(m)
				else:
					try:
						st = os.stat(self.pipe)
						if st.st_size == 0 and was_nondefault:
							self.change_image.emit('CLOSE')
					except FileNotFoundError:
						pass

					time.sleep(0.05)

class AnimationTimer(PipeThread):
	next_frame = pyqtSignal()
	start_animation = pyqtSignal(int, int)

	def run(self):
		while True:
			while not os.path.exists(self.pipe): time.sleep(0.1)

			pipe = open(self.pipe, 'r')
			pipe.flush()

			while os.path.exists(self.pipe): # Make sure the file still exists and wasn't cleaned up by SyngleChance
				message = os.read(pipe.fileno(), 256)
				if len(message) > 0:
					m = message.decode()
					if not ',' in m: pass
					last_line = m.splitlines()[-1]
					x, y = last_line.split(',')
					self.start_animation.emit(int(x), int(y))

					while True:
						self.next_frame.emit()
						time.sleep(1.0 / 60)
					
				time.sleep(0.05)

class Journal(QWidget):
	def __init__(self, *args, **kwargs):
		self.app = kwargs['app']
		del kwargs['app']

		super().__init__(*args, **kwargs)

		self.mousedown = False
		self.mousedownpos = QPoint(0, 0)

		self.label = QLabel(self)

		self.close_label = QLabel(self)
		self.close_label.setPixmap(QPixmap(os.path.join(base_path, 'images', 'close.png')))
		if not left_close: self.close_label.move(776, 0) # X = 800-24

		self.close_button = True

		self.change_image('default_en')

		if 'linux' in sys.platform: self.setWindowFlags(Qt.FramelessWindowHint)
		else: self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)
		self.setAttribute(Qt.WA_TranslucentBackground)
		self.setMouseTracking(True)
		self.setWindowTitle(' ')
		self.setMinimumSize(800, 600)
		self.setMaximumSize(800, 600)
		self.setGeometry(0, 0, 800, 600)

		self.show()

	def mousePressEvent(self, event):
		self.mousedown = True
		self.mousedownpos = event.pos()

		if self.close_button and (((left_close and self.mousedownpos.x() <= 24) or (not left_close and self.mousedownpos.x() >= 776)) and self.mousedownpos.y() < 24):
			self.app.quit()

	def mouseReleaseEvent(self, event):
		self.mousedown = False

	def mouseMoveEvent(self, event):
		if event.buttons() == Qt.LeftButton:
			pos = event.pos()
			frameGm = self.frameGeometry()
			self.setGeometry(frameGm.x() + pos.x() - self.mousedownpos.x(), frameGm.y() + pos.y() - self.mousedownpos.y(), 800, 600)

	def change_image(self, image):
		if image == 'CLOSE':
			self.app.quit()
			return
		if not '_' in image: return

		name, lang = image.split('_', 1)

		if name == 'default' or name == 'save' or name == 'final':
			self.close_label.show()
			self.close_button = True
		else:
			self.close_label.hide()
			self.close_button = False

		img = img_en = os.path.join(base_path, 'images', '{}.png'.format(name))
		if lang != 'en':
			img = os.path.join(base_path, 'images', lang.upper(), '{}.png'.format(name))
			if not os.path.exists(img):
				print("No image {!r} for locale {!r}".format(name, lang), file=sys.stderr)
				img = img_en

		if not os.path.exists(img):
			print("Image not found: {!r}".format(img), file=sys.stderr)
			return

		self.pixmap = QPixmap(img)
		self.label.setPixmap(self.pixmap)

class Niko(QWidget):
	def __init__(self, *args, **kwargs):
		self.app, self.thread = kwargs['app'], kwargs['thread']
		self.screen_height = kwargs['screen_height']
		del kwargs['screen_height'], kwargs['app'], kwargs['thread']

		super().__init__(*args, **kwargs)

		self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
		self.setAttribute(Qt.WA_TranslucentBackground)
		self.setMinimumSize(48, 64)
		self.setMaximumSize(48, 64)

		self.label = QLabel(self)
		self.frames = [QPixmap(os.path.join(base_path, 'images', 'niko{}.png'.format(n))) for n in range(1,4)]
		self.label.setPixmap(self.frames[1])

	def start(self, x, y):
		self.x = x
		self.y = y
		self.start_y = y

		self.show()

	def getFrame(self):
		if ((self.y - self.start_y) % 32 >= 16): return 1
		if ((self.y - self.start_y) % 64 >= 32): return 0
		else: return 2

	def update(self):
		self.label.setPixmap(self.frames[self.getFrame()])
		self.y += 2
		if self.y > self.screen_height:
			self.app.quit()
			return
		elif self.y > self.screen_height - 64:
			self.setMinimumSize(48, self.screen_height - self.y)
			self.resize(48, self.screen_height - self.y)
		self.move(self.x, self.y)

if __name__ == '__main__':
	app = QApplication(sys.argv)

	pipe_path = get_pipe_path()
	if len(sys.argv) == 2 and sys.argv[1] == 'niko':
		# "Niko-leaves-the-screen" mode.
		pipe_path = get_pipe_path('niko')
		thread = AnimationTimer(pipe = pipe_path)

		niko = Niko(screen_height = app.primaryScreen().size().height(), app = app, thread = thread)

		thread.start_animation.connect(niko.start)
		thread.next_frame.connect(niko.update)
		thread.start()

	else:
		# Author's Journal mode.
		journal = Journal(app = app)
		save_path = os.path.join(get_documents_path(), 'Oneshot', 'save_progress.oneshot')
		if os.path.exists(save_path):
			with open(save_path, 'rb') as save:
				save.seek(-8, os.SEEK_END)
				lang = save.read().decode('utf-8')
				lang = lang[lang.find('[') + 1:lang.find(']')]
				if lang == 'en_US': lang = 'en'
				journal.change_image('save_' + lang)
		thread = WatchPipe(pipe = pipe_path)
		thread.change_image.connect(journal.change_image)
		thread.start()

	if not os.path.exists(pipe_path):
		pipe_file = open(pipe_path, 'w+')
		pipe_file.close()

	app.exec_()

	try:
		os.remove(pipe_path)
	except:
		# Most likely due to the file being in use, ignore.
		pass
