#!/usr/bin/env python3
# 
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

import os

from qiling import Qiling

from .. import utils

# exit
def __leaf_4c(ql: Qiling):
	ql.log.info("Program terminated gracefully")
	ql.emu_stop()

# write a character to screen
def __leaf_02(ql: Qiling):
	ch = ql.arch.regs.dl
	ql.arch.regs.al = ch

	print(f'{ch:c}', end='')

# write a string to screen
def __leaf_09(ql: Qiling):
	print(utils.read_dos_string_from_ds_dx(ql))

# clear input buffer
def __leaf_0c(ql: Qiling):
	pass

# set interrupt vector
def __leaf_25(ql: Qiling):
	pass

# create psp
def __leaf_26(ql: Qiling):
	pass

# get dos version
def __leaf_30(ql: Qiling):
	ql.arch.regs.ax = ql.os.dos_ver

# get or set ctrl-break
def __leaf_33(ql: Qiling):
	pass

# get interrupt vector
def __leaf_35(ql: Qiling):
	pass

# open file for write
def __leaf_3c(ql: Qiling):
	# fileattr ignored
	fname = utils.read_dos_string_from_ds_dx(ql)
	fpath = ql.os.path.transform_to_real_path(fname)

	ql.os.handles[ql.os.handle_next] = open(fpath, "wb")
	ql.arch.regs.ax = ql.os.handle_next
	ql.os.handle_next += 1
	ql.os.clear_cf()

# open file for read
def __leaf_3d(ql: Qiling):
	fname = utils.read_dos_string_from_ds_dx(ql)
	fpath = ql.os.path.transform_to_real_path(fname)

	ql.os.handles[ql.os.handle_next] = open(fpath, "rb")
	ql.arch.regs.ax = ql.os.handle_next
	ql.os.handle_next += 1
	ql.os.clear_cf()

# close file
def __leaf_3e(ql: Qiling):
	hd = ql.arch.regs.bx

	if hd in ql.os.handles:
		f = ql.os.handles.pop(hd)
		f.close()

		ql.os.clear_cf()
	else:
		ql.arch.regs.ax = 0x06
		ql.os.set_cf()

# read from file
def __leaf_3f(ql: Qiling):
	hd = ql.arch.regs.bx

	if hd in ql.os.handles:
		f = ql.os.handles[hd]
		buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx)
		sz = ql.arch.regs.cx
		rd = f.read(sz)
		ql.mem.write(buffer, rd)
		ql.os.clear_cf()
		ql.arch.regs.ax = len(rd)
	else:
		ql.arch.regs.ax = 0x06
		ql.os.set_cf()

# write to file
def __leaf_40(ql: Qiling):
	hd = ql.arch.regs.bx

	if hd in ql.os.handles:
		f = ql.os.handles[hd]
		buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx)
		sz = ql.arch.regs.cx
		rd = ql.mem.read(buffer, sz)
		f.write(bytes(rd))
		ql.os.clear_cf()
		ql.arch.regs.ax = len(rd)
	else:
		ql.arch.regs.ax = 0x06
		ql.os.set_cf()

# delete file
def __leaf_41(ql: Qiling):
	fname = utils.read_dos_string_from_ds_dx(ql)
	fpath = ql.os.path.transform_to_real_path(fname)

	try:
		os.remove(fpath)
		ql.os.clear_cf()
	except OSError:
		ql.arch.regs.ax = 0x05
		ql.os.set_cf()

def __leaf_43(ql: Qiling):
	ql.arch.regs.cx = 0xffff
	ql.os.clear_cf()

def handler(ql: Qiling):
	ah = ql.arch.regs.ah

	leaffunc = {
		0x02 : __leaf_02,
		0x06 : __leaf_02,
		0x09 : __leaf_09,
		0x0c : __leaf_0c,
		0x25 : __leaf_25,
		0x26 : __leaf_26,
		0x30 : __leaf_30,
		0x33 : __leaf_33,
		0x35 : __leaf_35,
		0x3c : __leaf_3c,
		0x3d : __leaf_3d,
		0x3e : __leaf_3e,
		0x3f : __leaf_3f,
		0x40 : __leaf_40,
		0x41 : __leaf_41,
		0x43 : __leaf_43,
		0x4c : __leaf_4c
	}.get(ah)

	if leaffunc is None:
		ql.log.exception(f'leaf {ah:02x}h of INT 21h is not implemented')
		raise NotImplementedError()

	leaffunc(ql)
