#!/usr/bin/env python3

import re
import os
import sys
import curses
from curses import ascii

import logging

import irank

LIST_MODE = False
A_STAR = None
A_KEY = None
A_FILENAME = None

NEXT = 1
PREVIOUS = -1
STAR = "*"

class Editor(object):
	def __init__(self, *songs):
		self.songs = songs
		self.lines = []
		self.selected_line = 0
		logging.basicConfig(level=logging.DEBUG, filename='/tmp/irank-editor-curses.log')
	
	def draw(self):
		self.win_height, self.win_width = self.scr.getmaxyx()
		self.scr.clear()
		self.draw_filename()
		self.draw_ratings()
		self.scr.refresh()
	
	def draw_filename(self):
		filename_start = min((self.win_width - len(self.filename)) // 4, 20)
		if filename_start < 0: filename_start = 0
		self.scr.insnstr(0, filename_start, self.filename, self.win_width, A_FILENAME)
	
	def draw_ratings(self):
		indent = 3
		y_start = 2
		margin = 1
		i = 0
		for key, rating in self.song.values.formatted_pairs():
			if self.selected_line == i:
				attr = curses.A_REVERSE
			else:
				attr = 0
			
			# Fun bug with curses+tilda; multiple spaces get collapsed into a single
			# space if there are between 7 and 13 of them, inclusive.
			# Less than 7 spaces works fine, and 14 or more work fine too.
			# Life is too short to figure out why.
			strippped = key.strip()
			num_spaces = len(key) - len(strippped)
			self.scr.insstr(i + y_start, indent+num_spaces, strippped, A_KEY | attr)
			# self.scr.insstr(i + y_start, indent, key, A_KEY | attr)
			self.scr.insstr(i + y_start, indent + len(key) + margin, rating, A_STAR | attr)

			i += 1


	def main(self, scr):
		self.init_colors()
		self.scr = scr
		for song in self.songs:
			self.filename = song
			self.selected_line = 0
			self.song = irank.Song(song)
			self.draw()
			logging.debug("editing song: %s" % (song,))

			def save():
				logging.debug("Saving file %s with comment: %s" % (
					self.filename, self.song.values.flatten()))
				self.song.save()

			while True:
				ch = self.scr.getch()
				if ch == ascii.NL:
					save()
					break
				elif ch == curses.KEY_UP or ch == ord('k'):
					self.select(PREVIOUS)
				elif ch == curses.KEY_DOWN or ch == ord('j'):
					self.select(NEXT)
				elif ch == curses.KEY_LEFT or ch == ord(' ') or ch == ord('h'):
					self.add_rating(-1)
				elif ch == curses.KEY_RIGHT or ch == ord('l'):
					self.add_rating(1)
				elif ch == curses.KEY_HOME or ch == ord('g'):
					self.move_to(0)
				elif ch == curses.KEY_END or ch == ord('G'):
					self.move_to(len(self.song.values)-1)
				elif ch == ascii.ESC:
					break
				elif ch == ascii.EOT: # ctrl-D
					return
				elif ascii.isprint(ch) and ascii.unctrl(ch) in "12345":
					self.set_rating(int(ascii.unctrl(ch)))
				elif ascii.isprint(ch) and ascii.unctrl(ch) == '`':
					self.set_rating(0)
				self.draw()

	def init_colors(self):
		global A_STAR, A_KEY, A_FILENAME
		curses.use_default_colors()
		curses.curs_set(0) # hide cursor

		n_star = 1
		n_key = 2
		n_filename = 3
		bg_index = -1

		curses.init_pair(n_filename, curses.COLOR_WHITE, bg_index)
		curses.init_pair(n_star, curses.COLOR_YELLOW, bg_index)
		curses.init_pair(n_key, curses.COLOR_WHITE, bg_index)

		A_FILENAME = curses.color_pair(n_filename)
		A_KEY = curses.color_pair(n_key) | curses.A_BOLD
		A_STAR = curses.color_pair(n_star)

	def move_to(self, index):
		self.selected_line = index
	
	def select(self, amount):
		self.selected_line += amount
		max_line = len(self.song.values) - 1
		if self.selected_line < 0: self.selected_line = 0
		if self.selected_line > max_line: self.selected_line = max_line
	
	def add_rating(self, amount):
		rating_key = self.song.values.keys()[self.selected_line]
		rating = self.song.values[rating_key]
		rating += amount
		if rating < 0: rating = 0
		if rating > 5: rating = 5
		self.song.values[rating_key] = rating
		logging.debug("set key %s to %s" % (rating_key, rating))
	
	def set_rating(self, rating):
		rating_key = self.song.values.keys()[self.selected_line]
		self.song.values[rating_key] = rating

def main(*args):
	try:
		curses.wrapper(Editor(*args).main)
	except (EOFError, KeyboardInterrupt): pass

