﻿//----------------------------------------------------------------------------//
//                                                                            //
// Z80 Emulator Core Library 2 (c) 2017 Søren Amtorp                          //
//                                                                            //
// Permission is hereby granted, free of charge, to any person obtaining a    //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation  //
// the rights to use, copy, modify, merge, publish, distribute, sublicense,   //
// and/or sell copies of the Software, and to permit persons to whom the      //
// Software is furnished to do so, subject to the following conditions:       //
//                                                                            //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software.                        //
//                                                                            //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        //
// DEALINGS IN THE SOFTWARE.                                                  //
//                                                                            //
//----------------------------------------------------------------------------//
//
// RC2014 
//
// A simple RC2014 emulator. It emulate RC2014 in its simplest form like when 
// you get the full monty build at running for the first time. It also serves 
// as an example of how you can use the bare bone Z80 emulator with your own
// memory and i/o handling.
//


using System;
using System.Drawing;
using System.Windows.Forms;
using Z80lib.Emulator;
using Z80lib;

namespace RC2014
{
    public partial class FormRC2014 : Form
    {
        IZ80 vZ80;
        IoHandler vIoHandler;
        char[][] vScreenBuffer;
        SizeF vCharSize;
        Win32Caret vCursor; // this will defenitly not work with mono on linux

        public FormRC2014()
        {
            InitializeComponent();
            vCharSize = CharSize(Font);
            SetSize();
            vScreenBuffer = new char[24][];
            for (int y = 0; y < 24; ++y)
            {
                vScreenBuffer[y] = new char[80];
                for (int x = 0; x < 80; ++x)
                {
                    vScreenBuffer[y][x] = ' ';
                }
            }
            vCursor = new Win32Caret(this);
            vCursor.Create((int)vCharSize.Width, 4);
            vZ80 = Z80library.GetEmulator();
            vZ80.Memory = new MemoryHandler();
            vIoHandler = new IoHandler(vZ80, vScreenBuffer);
            vZ80.Io = vIoHandler;
            Application.Idle += Idle;
        }

        private void RC2014_Paint(object sender, PaintEventArgs e)
        {
            Graphics gr = e.Graphics;
            Brush br = new SolidBrush(ForeColor);

            for (int y = 0; y < 24; ++y)
            {
                for (int x = 0; x < 80; ++x)
                {
                    gr.DrawString(vScreenBuffer[y][x].ToString(), Font, br, (x * vCharSize.Width), (y * vCharSize.Height));
                }

                vCursor.SetPosition((int)(vIoHandler.Xpos * vCharSize.Width) + 4, (int)((vIoHandler.Ypos * vCharSize.Height) + (vCharSize.Height - 7)));
            }
        }

        private void FormRC2014_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                vCursor.Show();
            }
            else
            {
                vCursor.Hide();
            }
        }

        private void RC2014_KeyPress(object sender, KeyPressEventArgs e)
        {
            vIoHandler.KeyChar(e.KeyChar);
        }

        private void SetSize()
        {
            Width = (int)(vCharSize.Width * 80) + (Width - ClientRectangle.Width) + (int)vCharSize.Width;
            Height = (int)(vCharSize.Height * 24) + (Height - ClientRectangle.Height) + 3;
        }

        private void Idle(object sender, EventArgs e)
        {
            do
            {
                for (ushort u = 1; u != 0; ++u)
                {
                    vZ80.ExecuteNext();
                }
                Update();
                Application.DoEvents();
            }
            while (Visible);
        }

        public SizeF MeasureString(string pString, Font pFont)
        {
            SizeF result;
            using (var image = new Bitmap(1, 1))
            {
                using (var g = Graphics.FromImage(image))
                {
                    result = g.MeasureString(pString, pFont);
                }
            }

            return result;
        }

        public SizeF CharSize(Font pFont)
        {
            SizeF result = MeasureString(new string('X', 100), pFont);
            result.Width /= 100f;
            return result;
        }
    }
}
