/* aicon.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2019 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "aguix.h"
#include "aicon.hh"
#include <iostream>

AIcon::AIcon( AGUIX *aguix,
              Drawable d,
              const int *pixels,
              size_t pixels_length ) :
    m_aguix( aguix ),
    m_d( d ),
    m_w( 0 ),
    m_h( 0 ),
    m_scale_factor( 0 ),
    m_aguix_color_instance( -1 ),
    m_current_fg( -1 ),
    m_current_bg( -1 )
{
    if ( pixels_length < 3 ) {
        std::cerr << "Invalid pixels field" << std::endl;
        return;
    }

    size_t w = pixels[0];
    size_t h = pixels[1];

    if ( w * h + 2 != pixels_length ) {
        std::cerr << "Invalid pixels field" << std::endl;
        return;
    }

    m_w = w;
    m_h = h;

    for ( size_t p = 0; p < w * h; p++ ) {
        m_pixels.push_back( pixels[ 2 + p ] );
    }

    update( 1, 0, true );
}

AIcon::~AIcon()
{
    cleanPixmapCache();
}

void AIcon::update( Drawable d, int fg, int bg, bool force )
{
    if ( m_d != d ) {
        m_d = d;
        force = true;
    }

    update( fg, bg, force );
}

void AIcon::update( int fg, int bg, bool force )
{
    if ( m_d == 0 ) return;

    if ( m_w < 1 || m_h < 1 ) return;

    if ( ! force &&
         m_current_fg == fg &&
         m_current_bg == bg &&
         m_aguix_color_instance == m_aguix->getCurrentUserColorInstance() ) {
        return;
    }

    auto id = std::make_pair( fg, bg );

    if ( m_aguix_color_instance != m_aguix->getCurrentUserColorInstance() ) {
        // remove cache
        cleanPixmapCache();
    }
    
    bool skip_update = false;

    if ( m_pixmap_cache.count( id ) > 0 ) {
        if ( ! force ) {
            skip_update = true;
        } else {
            m_aguix->freePixmap( m_pixmap_cache[id] );
            m_pixmap_cache.erase( id );
        }
    }

    if ( ! skip_update ) {
        size_t factor = 1;
        if ( m_scale_factor > 1 ) {
            factor = m_scale_factor;
        }
    
        Pixmap pixmap = m_aguix->createPixmap( m_d, m_w * factor, m_h * factor );

        if ( pixmap != 0 ) {
            AGUIX::col_values_t fg_values = m_aguix->getColorInfo( fg );
            AGUIX::col_values_t bg_values = m_aguix->getColorInfo( bg );

            for ( size_t y = 0; y < m_h * factor; y++ ) {
                for ( size_t x = 0; x < m_w * factor; x++ ) {
                    int c = m_pixels.at( ( y / factor ) * m_w + x / factor );

                    AGUIX::col_values_t color = m_aguix->blend( bg_values,
                                                                fg_values,
                                                                c );

                    AGUIXColor acol = m_aguix->getColor( color );

                    m_aguix->setFG( acol );

                    m_aguix->DrawPoint( pixmap, x, y );
                }
            }

            m_pixmap_cache[id] = pixmap;
        }
    }

    m_current_fg = fg;
    m_current_bg = bg;
    m_aguix_color_instance = m_aguix->getCurrentUserColorInstance();
}

void AIcon::draw( Drawable d,
                  int x, int y )
{
    try {
        Pixmap pixmap = m_pixmap_cache.at( std::make_pair( m_current_fg,
                                                           m_current_bg ) );

        size_t factor = 1;
        if ( m_scale_factor > 1 ) {
            factor = m_scale_factor;
        }
    
        m_aguix->copyArea( pixmap,
                           d,
                           0, 0,
                           m_w * factor, m_h * factor,
                           x, y );
    } catch (...) {
    }
}

size_t AIcon::w() const
{
    return m_w;
}

size_t AIcon::h() const
{
    return m_h;
}

void AIcon::setScale( size_t factor )
{
    m_scale_factor = factor;
}

Drawable AIcon::drawable() const
{
    return m_d;
}

void AIcon::cleanPixmapCache()
{
    for ( auto it : m_pixmap_cache ) {
        m_aguix->freePixmap( it.second );
    }
    m_pixmap_cache.clear();
}
