/* informationmode.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2026 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 "informationmode.h"
#include "listermode.h"
#include "worker_locale.h"
#include "wconfig.h"
#include "worker.h"
#include "partspace.h"
#include "pdatei.h"
#include "wcfiletype.hh"
#include "fileentry.hh"
#include "nmspecialsourceext.hh"
#include "aguix/acontainer.h"
#include "aguix/fieldlistview.h"
#include "aguix/awindow.h"
#include "aguix/util.h"
#include "datei.h"
#include "nwc_path.hh"
#include "nwcentryselectionstate.hh"

const char *InformationMode::type="InformationMode";

enum lv_infomode_rows {
    IM_NAME = 1,
    IM_SIZE,
    IM_FILETYPE,
    IM_FILE_OUTPUT,
    IM_MIMETYPE,
    IM_CRUNCHER,
    IM_LINK_DEST,
    IM_CUSTOM_ATTRIBUTE,
    IM_PERMISSIONS_USER = IM_CUSTOM_ATTRIBUTE + 2,
    IM_PERMISSIONS_GROUP,
    IM_PERMISSIONS_OTHER,
    IM_PERMISSIONS_NUMERICAL,
    IM_FILE_OWNER,
    IM_INODE,
    IM_NLINK,
    IM_ACCESSTIME = IM_NLINK + 2,
    IM_MODTIME,
    IM_CHANGETIME,
    IM_FULLNAME = IM_CHANGETIME + 2,
    IM_REALPATH,
    IM_FREESPACE = IM_REALPATH + 2,

    IM_ELEMENT_COUNT
};

InformationMode::InformationMode(Lister *parent):ListerMode(parent)
{
  lastactivefe=NULL;
  lv=NULL;
  blanked=false;
  nospaceinfo=false;
  m_cont = NULL;
}

InformationMode::~InformationMode()
{
  clearLastActiveFE();
}

void InformationMode::messageHandler(AGMessage *msg)
{
  bool ma=false;
  switch(msg->type) {
    case AG_SIZECHANGED:
      break;
  }
  if(ma==true) parentlister->makeActive();
}

void InformationMode::on()
{
  int side=parentlister->getSide();
  int m;

  m_cont = new AContainer( parentawindow, 1, 1 );
  m_cont->setBorderWidth( 0 );
  m_cont->setMinSpace( 0 );
  m_cont->setMaxSpace( 0 );
  parentlister->setContainer( m_cont );

  lv = (FieldListView*)m_cont->add( new FieldListView( aguix, 0, 0, 50, 50, 1 ),
                                    0, 0 );
  m=(wconfig->getHBarTop(side)==true)?1:2;
  lv->setHBarState(m);
  m=(wconfig->getVBarLeft(side)==true)?1:2;
  lv->setVBarState(m);
  m=wconfig->getHBarHeight(side);
  lv->setHBarHeight(m);
  m=wconfig->getVBarWidth(side);
  lv->setVBarWidth(m);
  lv->setFont( wconfig->getFont( 2 + side ).c_str() );
  
  lv->setSize( IM_ELEMENT_COUNT );
  lv->setNrOfFields( 2 );
  lv->setFieldSpace( 1, 5 );

  for ( m = 0; m < IM_ELEMENT_COUNT; m++ ) {
    lv->setText( m, 0, "" );
    lv->setPreColors( m, FieldListView::PRECOLOR_NOTSELORACT );
  }

  parentlister->setActiveMode(this);
  setName();

  parentawindow->updateCont();
}

void InformationMode::off()
{
  delete lv;
  lv = NULL;
  parentlister->setContainer( NULL );
  delete m_cont;
  m_cont = NULL;
  parentlister->setActiveMode(NULL);
  parentlister->setName("");
  clearLastActiveFE();
}

void InformationMode::activate()
{
}

void InformationMode::deactivate()
{
}

bool InformationMode::isType(const char *str)
{
  if(strcmp(str,type)==0) return true; else return false;
}

const char *InformationMode::getType()
{
  return type;
}

const char *InformationMode::getStaticType()
{
  return type;
}


int InformationMode::configure()
{
  return 0;
}

void InformationMode::cyclicfunc(cyclicfunc_mode_t mode)
{
  update(false);
}

const char* InformationMode::getLocaleName()
{
  return getStaticLocaleName();
}

const char* InformationMode::getStaticLocaleName()
{
  return catalog.getLocale(175);
}

int InformationMode::load()
{
  return 0;
}

bool InformationMode::save(Datei *fh)
{
  return false;
}

void InformationMode::setName()
{
  parentlister->setName(catalog.getLocale(175));
}

void InformationMode::relayout()
{
    int side = parentlister->getSide();
    lv->setFont( wconfig->getFont( 2 + side ).c_str() );
}

void InformationMode::update(bool force)
{
    ListerMode *lm1=NULL;
    Lister *ol=NULL;
    const FileEntry *fe;
  
    ol=parentlister->getWorker()->getOtherLister(parentlister);
    if(ol!=NULL) {
        lm1=ol->getActiveMode();
    }
  
    if ( ( force == true ) ||
         ( nospaceinfo == true ) ) {
        clearLastActiveFE();
    }
  
    if(lm1!=NULL) {
        std::list< NM_specialsourceExt > files;
    
        lm1->getSelFiles( files, ListerMode::LM_GETFILES_ONLYACTIVE, false, ListerMode::LM_GETFILES_OPTION_CUSTOM_ATTRIBUTES );

        if ( ! files.empty() ) {
            fe = files.begin()->entry();
            if ( fe->equals( lastactivefe ) == false ) {
                clearLastActiveFE();
                if ( fe != NULL ) {
                    lastactivefe = new FileEntry( *fe );
                    m_custom_attribute = files.begin()->customAttribute();
                }
                showinfos();
            }
        } else {
            if ( ol->isActive() == true ) {
                // only clear LV when other side is active and has no active fe
                if ( lastactivefe != NULL ) {
                    clearLastActiveFE();
                    showinfos();
                }
            }
        }
    }
}

void InformationMode::showinfos()
{
    FileEntry *fe;
    char rights[3][4];
    char *str;
    bool showno;
    loff_t size;
    const char *cstr;
    std::string bytestr, kbytestr, mbytestr, bstr1;
  
    float percent;
    time_t tvar;
    char *istr;
    std::string tstr2;
  
    showno = true;
    fe = lastactivefe;

    if ( fe != NULL ) {
        showno = false;
        lv->setText( IM_NAME, 0, std::string( catalog.getLocale( 176 ) ) + ":" );
        lv->setText( IM_NAME, 1, fe->name );
    
        if ( fe->isDir() == true && fe->isCorrupt == false ) {
            if ( fe->dirsize >= 0 ) size = fe->dirsize;
            else size = fe->size();
        } else {
            size = fe->size();
        }

        MakeLong2NiceStr( size, bytestr );

        MakeLong2NiceStr( ( size + 512 ) / 1024, kbytestr );

        MakeLong2NiceStr( ( size + 524288 ) / 1048576, mbytestr );

        MakeLong2NiceStr( fe->blocks(), bstr1, false );
        tstr2 = AGUIXUtils::formatStringToString( catalog.getLocale( 551 ),
                                                  bstr1.c_str() );

        lv->setText( IM_SIZE, 0, std::string( catalog.getLocale( 177 ) ) + ":" );
        lv->setText( IM_SIZE, 1, AGUIXUtils::formatStringToString( "%s B, %s KB, %s MB (%s)",
                                                                   bytestr.c_str(),
                                                                   kbytestr.c_str(),
                                                                   mbytestr.c_str(),
                                                                   tstr2.c_str() ) );

        lv->setText( IM_FILETYPE, 0, std::string( catalog.getLocale( 178 ) ) + ":" );
        lv->setText( IM_FILE_OUTPUT, 0, std::string( catalog.getLocale( 1592 ) ) + ":" );
        lv->setText( IM_MIMETYPE, 0, std::string( catalog.getLocale( 1593 ) ) + ":" );
        if ( fe->filetype != NULL ) {
            auto fpr = std::make_shared< NWCFlagProducer >( nullptr, fe );
            FlagReplacer rpl( fpr );
            std::string filetype_str;

            if ( fe->filetype->nameContainsFlags() ) {
                filetype_str = rpl.replaceFlags( fe->filetype->getName(), false );
            } else {
                filetype_str = fe->filetype->getName();
            }

            lv->setText( IM_FILETYPE, 1, filetype_str );

            if ( ! fe->getFiletypeFileOutput().empty() ) {
                lv->setText( IM_FILE_OUTPUT, 1, fe->getFiletypeFileOutput().c_str() );
                lv->setText( IM_MIMETYPE, 1, fe->getMimeType().c_str() );
            } else {
                lv->setText( IM_FILE_OUTPUT, 1, "" );
                lv->setText( IM_MIMETYPE, 1, "" );
            }
        } else {
            if ( fe->isDir() == true ) {
                lv->setText( IM_FILETYPE, 1, wconfig->getdirtype()->getName() );
            } else {
                lv->setText( IM_FILETYPE, 1, wconfig->getnotyettype()->getName() );
            }
            lv->setText( IM_FILE_OUTPUT, 1, "" );
            lv->setText( IM_MIMETYPE, 1, "" );
        }

        lv->setText( IM_CRUNCHER, 0, std::string( catalog.getLocale( 1594 ) ) + ":" );
        lv->setText( IM_CRUNCHER, 1, "" );

        if ( fe->isCorrupt == false ) {
            // dmode is only accessed when not corrupt
            if ( S_ISREG( ( fe->isLink == true ) ? fe->dmode() : fe->mode() ) ) {
                enum PDatei::pdatei_handler pt;
        
                pt = PDatei::getCruncher( fe->fullname );
                switch ( pt ) {
                    case PDatei::PDATEI_XPK:
                        lv->setText( IM_CRUNCHER, 1, AGUIXUtils::formatStringToString( catalog.getLocale( 506 ),
                                                                             "XPK" ) );
                        break;
                    case PDatei::PDATEI_BZIP2:
                        lv->setText( IM_CRUNCHER, 1, AGUIXUtils::formatStringToString( catalog.getLocale( 506 ),
                                                                             "BZIP2" ) );
                        break;
                    case PDatei::PDATEI_GZIP:
                        lv->setText( IM_CRUNCHER, 1, AGUIXUtils::formatStringToString( catalog.getLocale( 506 ),
                                                                             "GZIP" ) );
                        break;
                    case PDatei::PDATEI_NORMAL:
                        lv->setText( IM_CRUNCHER, 1, catalog.getLocale( 507 ) );
                        break;
                    default:
                        lv->setText( IM_CRUNCHER, 1, "???" );
                        break;
                }
            } 
        }

        if ( fe->isLink == true ) {
            lv->setText( IM_LINK_DEST, 0, std::string( catalog.getLocale( 179 ) ) + ":" );
            str = fe->getDestination();
      
            if ( str != NULL ) {
                lv->setText( IM_LINK_DEST, 1, str);
                _freesafe(str);
            } else {
                lv->setText( IM_LINK_DEST, 1, "" );
            }
        } else {
            lv->setText( IM_LINK_DEST, 0, "" );
            lv->setText( IM_LINK_DEST, 1, "");
        }
    
        cstr = fe->getPermissionString();
        strncpy( rights[0], cstr + 1, 3 );
        rights[0][3] = '\0';
        strncpy( rights[1], cstr + 4, 3 );
        rights[1][3] = '\0';
        strncpy( rights[2], cstr + 7, 3 );
        rights[2][3] = '\0';

        lv->setText( IM_PERMISSIONS_USER, 0, AGUIXUtils::formatStringToString( "%s %s",
                                                                               catalog.getLocale( 180 ),
                                                                               catalog.getLocale( 214 ) ) );
        lv->setText( IM_PERMISSIONS_USER, 1, rights[0] );
        lv->setText( IM_PERMISSIONS_GROUP, 0, AGUIXUtils::formatStringToString( "%s %s",
                                                                                catalog.getLocale( 180 ),
                                                                                catalog.getLocale( 215 ) ) );
        lv->setText( IM_PERMISSIONS_GROUP, 1, rights[1] );
        lv->setText( IM_PERMISSIONS_OTHER, 0, AGUIXUtils::formatStringToString( "%s %s",
                                                                                catalog.getLocale( 180 ),
                                                                                catalog.getLocale( 216 ) ) );
        lv->setText( IM_PERMISSIONS_OTHER, 1, rights[2] );
    
        lv->setText( IM_PERMISSIONS_NUMERICAL, 0, AGUIXUtils::formatStringToString( "%s %s",
                                                                                    catalog.getLocale( 180 ),
                                                                                    catalog.getLocale( 527 ) ) );
        lv->setText( IM_PERMISSIONS_NUMERICAL, 1, AGUIXUtils::formatStringToString( "%04o",
                                                                                    (unsigned int)( ( fe->mode() ) & 07777 ) ) );

        str = getOwnerString( fe->userid(), fe->groupid() );
        lv->setText( IM_FILE_OWNER, 0, std::string( catalog.getLocale( 184 ) ) + ":" );
        lv->setText( IM_FILE_OWNER, 1, str );
        _freesafe(str);

        MakeLong2NiceStr( (loff_t)fe->inode(), bstr1, false );
        lv->setText( IM_INODE, 0, std::string( catalog.getLocale( 548 ) ) + ":" );
        lv->setText( IM_INODE, 1, bstr1 );

        MakeLong2NiceStr( (loff_t)fe->nlink(), bstr1, false );
        lv->setText( IM_NLINK, 0, std::string( catalog.getLocale( 549 ) ) + ":" );
        lv->setText( IM_NLINK, 1, bstr1 );

        tvar = fe->lastaccess();
        str = asctime( localtime( &( tvar ) ) );
        str[ strlen( str ) - 1 ] = 0;

        lv->setText( IM_ACCESSTIME, 0, std::string( catalog.getLocale( 162 ) ) + ":" );
        lv->setText( IM_ACCESSTIME, 1, str );

        tvar = fe->lastmod();
        str = asctime( localtime( &( tvar ) ) );
        str[ strlen( str ) - 1 ] = 0;

        lv->setText( IM_MODTIME, 0, std::string( catalog.getLocale( 163 ) ) + ":" );
        lv->setText( IM_MODTIME, 1, str );

        tvar = fe->lastchange();
        str = asctime( localtime( &( tvar ) ) );
        str[ strlen( str ) - 1 ] = 0;

        lv->setText( IM_CHANGETIME, 0, std::string( catalog.getLocale( 164 ) ) + ":" );
        lv->setText( IM_CHANGETIME, 1, str );

        lv->setText( IM_FULLNAME, 0, std::string( catalog.getLocale( 185 ) ) + ":" );
        lv->setText( IM_FULLNAME, 1, fe->fullname );

        str = realpath( fe->fullname, NULL );
        lv->setText( IM_REALPATH, 0, std::string( catalog.getLocale( 186 ) ) + ":" );
        if ( str ) {
            lv->setText( IM_REALPATH, 1, str );
            free( str );
        } else {
            lv->setText( IM_REALPATH, 1, "???" );
        }

        lv->setText( IM_FREESPACE, 0, std::string( catalog.getLocale( 187 ) ) + ":" );
        if ( fe->isCorrupt == false ) {
            istr = dupstring( fe->fullname );
        } else {
            istr = NWC::Path::parentDir( fe->fullname, NULL );
        }
        if ( parentlister->getWorker()->PS_readSpace( istr ) == 0 ) {
            if ( parentlister->getWorker()->PS_getSpace() != 0 ) {
                percent = (double)parentlister->getWorker()->PS_getFreeSpace(); 
                percent *= 100.0;
                percent /= (double)parentlister->getWorker()->PS_getSpace();
            } else {
                percent = 0.0;
            }

            std::string spaceh, freeh;

            spaceh = parentlister->getWorker()->PS_getSpaceH();
            freeh = parentlister->getWorker()->PS_getFreeSpaceH();

            lv->setText( IM_FREESPACE, 1, AGUIXUtils::formatStringToString( "%s (%2.0f %%) %s %s",
                                                                            freeh.c_str(),
                                                                            percent,
                                                                            catalog.getLocale( 188 ),
                                                                            spaceh.c_str() ) );
            nospaceinfo = false;
        } else {
            lv->setText( IM_FREESPACE, 1, "???" );
            nospaceinfo = true;
        }
        _freesafe( istr );

        if ( ! m_custom_attribute.empty() ) {
            lv->setText( IM_CUSTOM_ATTRIBUTE, 0, std::string( catalog.getLocale( 1534 ) ) + ":" );
            lv->setText( IM_CUSTOM_ATTRIBUTE, 1, m_custom_attribute );
        } else {
            lv->setText( IM_CUSTOM_ATTRIBUTE, 0, "" );
            lv->setText( IM_CUSTOM_ATTRIBUTE, 1, "" );
        }
    }

    if ( showno == true ) {
        for ( int i = 0; i < lv->getElements(); i++ ) {
            lv->setText( i, 0, "" );
            lv->setText( i, 1, "" );
        }
        lv->setText( 2, 0, catalog.getLocale( 189 ) );
    }

    lv->redraw();
}

void InformationMode::clearLastActiveFE() {
  if ( lastactivefe != NULL ) {
    delete lastactivefe;
    lastactivefe = NULL;
  }
}
