/***************************************************************************
 *   Copyright (C) 2023 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include <QPainter>

#include "scriptdisplay.h"
#include "scriptcpu.h"
#include "simulator.h"

ScriptDisplay::ScriptDisplay( int w, int h, QString name, QWidget* parent )
             : DisplayArea( w, h, name, parent )
             , ScriptPerif( name )
{
    m_clear = nullptr; 

    m_type = "Display"; 

    m_methods << "setWidth( int pixels )"
              << "setHeight( int pixels )"
              << "setBackground( int RGB )"
              << "setPixel( uint x, uint y, int RGB )"
              << "setData( array<array<int>> &data )"
              << "void fillData( int data )"
              << "setPalette( array<int> &data )"
              << "setBGR( bool b )"
              << "drawLine( int x0, int y0, int x1, int y1, int color )"
              << "clear()"
                 ; 
}
ScriptDisplay::~ScriptDisplay(){}

QStringList ScriptDisplay::registerScript( ScriptCpu* cpu )
{
    m_scriptCpu = cpu; 

    asIScriptEngine* engine = cpu->engine(); 

    asITypeInfo* info = engine->GetTypeInfoByName("Display");  // Check if "Display is already registered
    if( !info ) registerScriptMetods( engine ); 

    string display = "Display "+m_perifName.toStdString();  // Type name
    engine->RegisterGlobalProperty( display.c_str(), this ); 

    return m_methods; 
}

void ScriptDisplay::registerScriptMetods( asIScriptEngine* engine ) // Static: register Object type and methods only once
{
    engine->RegisterObjectType("Display", 0, asOBJ_REF | asOBJ_NOCOUNT ); 

    engine->RegisterObjectMethod("Display", "void setWidth(int w)"
                                   , asMETHODPR( ScriptDisplay, setWidth, (uint), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setHeight(int h)"
                                   , asMETHODPR( ScriptDisplay, setHeight, (uint), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setBackground(int b)"
                                   , asMETHODPR( ScriptDisplay, setBackground, (int), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setPixel(uint x, uint y, int color)"
                                   , asMETHODPR( ScriptDisplay, setPixel, (uint,uint,int), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void drawLine( int x0, int y0, int x1, int y1, int color )"
                                   , asMETHODPR( ScriptDisplay, drawLine, (int,int,int,int,int), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setData( array<array<int>> &data )"
                                   , asMETHODPR( ScriptDisplay, setData, (CScriptArray*), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void fillData( int data )"
                                 , asMETHODPR( ScriptDisplay, fillData, (int), void)
                                 , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setPalette( array<int> &data )"
                                   , asMETHODPR( ScriptDisplay, setPalette, (CScriptArray*), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void clear()"
                                   , asMETHODPR( ScriptDisplay, clear, (), void)
                                   , asCALL_THISCALL ); 

    engine->RegisterObjectMethod("Display", "void setBGR(bool b)"
                                 , asMETHODPR( ScriptDisplay, setBGR, (bool), void)
                                 , asCALL_THISCALL ); 
}

void ScriptDisplay::startScript()
{
    asIScriptEngine* aEngine = m_scriptCpu->engine(); 

    m_clear = aEngine->GetModule(0)->GetFunctionByDecl("void clear()"); 
}

void ScriptDisplay::initialize()
{
    if( m_clear ) m_scriptCpu->callFunction( m_clear ); 
}

void ScriptDisplay::setPalette( CScriptArray* p )
{
    m_palette.clear(); 

    for( uint x=0;  x<p->GetSize();  x++ )
    {
        int color = *(int*)p->At(x); 
        m_palette.push_back( color ); 
    }
}

void ScriptDisplay::setData( CScriptArray* data )
{
    asITypeInfo* ti = data->GetArrayObjectType(); 
    if( QString( ti->GetName() ) != "array" ) return; 

    CScriptArray* column = (CScriptArray*)data->At( 0 ); 
    uint width = (uint)data->GetSize(); 
    uint height = (uint)column->GetSize(); 

    for( uint x=0;  x<width;  x++ )
    {
        column = (CScriptArray*)data->At( x ); 
        for( uint y=0;  y<height;  y++ )
        {
            int color = 0; 
            uint index = *(uint*)column->At(y); 
            if( index < m_palette.size() ) color = m_palette.at( index ); 
            else                           color = index; 
            setPixel( x, y, color ); 
        }
    }
}
