/***************************************************************************
                          ksutils.cpp  -  K Desktop Planetarium
                             -------------------
    begin                : Mon Jan  7 10:48:09 EST 2002
    copyright            : (C) 2002 by Mark Hollomon
    email                : mhh@mindspring.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "ksutils.h"

#include "deepskyobject.h"
#include "skyobject.h"
#include "Options.h"

#include <QFile>
#include <QtNumeric>
#include <QUrl>
#include <QStandardPaths>

#include <cmath>
#include "auxiliary/kspaths.h"

namespace KSUtils {


bool openDataFile( QFile &file, const QString &s ) {
    QString FileName = KSPaths::locate(QStandardPaths::GenericDataLocation, s );
    if ( !FileName.isNull() ) {
        file.setFileName( FileName );
        return file.open( QIODevice::ReadOnly );
    }
    return false;
}

QString getDSSURL( const SkyPoint * const p ) {
        const DeepSkyObject *dso = 0;
        double height, width;

        double dss_default_size = Options::defaultDSSImageSize();
        double dss_padding = Options::dSSPadding();

        Q_ASSERT( p );
        Q_ASSERT( dss_default_size > 0.0 && dss_padding >= 0.0 );

        dso = dynamic_cast<const DeepSkyObject *>( p );

        // Decide what to do about the height and width
        if( dso ) {
            // For deep-sky objects, use their height and width information
            double a, b, pa;
            a = dso->a();
            b = dso->a() * dso->e(); // Use a * e instead of b, since e() returns 1 whenever one of the dimensions is zero. This is important for circular objects
            pa = dso->pa() * dms::DegToRad;

            // We now want to convert a, b, and pa into an image
            // height and width -- i.e. a dRA and dDec.
            // DSS uses dDec for height and dRA for width. (i.e. "top" is north in the DSS images, AFAICT)
            // From some trigonometry, assuming we have a rectangular object (worst case), we need:
            width = a * sin( pa ) + b * cos( pa );
            height = a * cos( pa ) + b * sin( pa );
            // 'a' and 'b' are in arcminutes, so height and width are in arcminutes

            // Pad the RA and Dec, so that we show more of the sky than just the object.
            height += dss_padding;
            width += dss_padding;
        }
        else {
            // For a generic sky object, we don't know what to do. So
            // we just assume the default size.
            height = width = dss_default_size;
        }
        // There's no point in tiny DSS images that are smaller than dss_default_size
        if( height < dss_default_size )
            height = dss_default_size;
        if( width < dss_default_size )
            width = dss_default_size;

        return getDSSURL( p->ra0(), p->dec0(), width, height );
}

QString getDSSURL( const dms &ra, const dms &dec, float width, float height, const QString & type) {
    const QString URLprefix( "http://archive.stsci.edu/cgi-bin/dss_search?" );
    QString URLsuffix = QString( "&e=J2000&f=%1&c=none&fov=NONE" ).arg(type);
    const double dss_default_size = Options::defaultDSSImageSize();

    char decsgn = ( dec.Degrees() < 0.0 ) ? '-' : '+';
    int dd = abs( dec.degree() );
    int dm = abs( dec.arcmin() );
    int ds = abs( dec.arcsec() );

    // Infinite and NaN sizes are replaced by the default size and tiny DSS images are resized to default size
    if( !qIsFinite( height ) || height <= 0.0 )
        height = dss_default_size;
    if( !qIsFinite( width ) || width <= 0.0)
        width = dss_default_size;

    // DSS accepts images that are no larger than 75 arcminutes
    if( height > 75.0 )
        height = 75.0;
    if( width > 75.0 )
        width = 75.0;

    QString RAString, DecString, SizeString;
    DecString = DecString.sprintf( "&d=%c%02d+%02d+%02d", decsgn, dd, dm, ds );
    RAString  = RAString.sprintf( "r=%02d+%02d+%02d", ra.hour(), ra.minute(), ra.second() );
    SizeString = SizeString.sprintf( "&h=%02.1f&w=%02.1f", height, width );

    return ( URLprefix + RAString + DecString + SizeString + URLsuffix );
}

QString toDirectionString( dms angle ) {
    // TODO: Instead of doing it this way, it would be nicer to
    // compute the string to arbitrary precision. Although that will
    // not be easy to localize.  (Consider, for instance, Indian
    // languages that have special names for the intercardinal points)
    // -- asimha

    static const char *directions[] = {
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "N"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "NNE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "NE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "ENE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "E"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "ESE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "SE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "SSE"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "S"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "SSW"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "SW"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "WSW"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "W"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "WNW"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "NW"),
        I18N_NOOP2( "Abbreviated cardinal / intercardinal etc. direction", "NNW"),
        I18N_NOOP2( "Unknown cardinal / intercardinal direction", "???")
    };

    int index = (int)( (angle.reduce().Degrees() + 11.25) / 22.5); // A number between 0 and 16 (inclusive) is expected
    if( index < 0 || index > 16 )
        index = 17; // Something went wrong.
    else
        index = ( ( index == 16 ) ? 0 : index );

    return i18nc( "Abbreviated cardinal / intercardinal etc. direction", directions[ index ] );
}

QList<SkyObject *> * castStarObjListToSkyObjList( QList<StarObject *> *starObjList ) {
    QList<SkyObject *> *skyObjList = new QList<SkyObject *>();
    foreach( StarObject *so, *starObjList ) {
        skyObjList->append( so );
    }
    return skyObjList;
}


QString constGenetiveFromAbbrev( const QString &code ) {
    if ( code == "And" ) return QString("Andromedae");
    if ( code == "Ant" ) return QString("Antliae");
    if ( code == "Aps" ) return QString("Apodis");
    if ( code == "Aqr" ) return QString("Aquarii");
    if ( code == "Aql" ) return QString("Aquilae");
    if ( code == "Ara" ) return QString("Arae");
    if ( code == "Ari" ) return QString("Arietis");
    if ( code == "Aur" ) return QString("Aurigae");
    if ( code == "Boo" ) return QString("Bootis");
    if ( code == "Cae" ) return QString("Caeli");
    if ( code == "Cam" ) return QString("Camelopardalis");
    if ( code == "Cnc" ) return QString("Cancri");
    if ( code == "CVn" ) return QString("Canum Venaticorum");
    if ( code == "CMa" ) return QString("Canis Majoris");
    if ( code == "CMi" ) return QString("Canis Minoris");
    if ( code == "Cap" ) return QString("Capricorni");
    if ( code == "Car" ) return QString("Carinae");
    if ( code == "Cas" ) return QString("Cassiopeiae");
    if ( code == "Cen" ) return QString("Centauri");
    if ( code == "Cep" ) return QString("Cephei");
    if ( code == "Cet" ) return QString("Ceti");
    if ( code == "Cha" ) return QString("Chamaeleontis");
    if ( code == "Cir" ) return QString("Circini");
    if ( code == "Col" ) return QString("Columbae");
    if ( code == "Com" ) return QString("Comae Berenices");
    if ( code == "CrA" ) return QString("Coronae Austrinae");
    if ( code == "CrB" ) return QString("Coronae Borealis");
    if ( code == "Crv" ) return QString("Corvi");
    if ( code == "Crt" ) return QString("Crateris");
    if ( code == "Cru" ) return QString("Crucis");
    if ( code == "Cyg" ) return QString("Cygni");
    if ( code == "Del" ) return QString("Delphini");
    if ( code == "Dor" ) return QString("Doradus");
    if ( code == "Dra" ) return QString("Draconis");
    if ( code == "Equ" ) return QString("Equulei");
    if ( code == "Eri" ) return QString("Eridani");
    if ( code == "For" ) return QString("Fornacis");
    if ( code == "Gem" ) return QString("Geminorum");
    if ( code == "Gru" ) return QString("Gruis");
    if ( code == "Her" ) return QString("Herculis");
    if ( code == "Hor" ) return QString("Horologii");
    if ( code == "Hya" ) return QString("Hydrae");
    if ( code == "Hyi" ) return QString("Hydri");
    if ( code == "Ind" ) return QString("Indi");
    if ( code == "Lac" ) return QString("Lacertae");
    if ( code == "Leo" ) return QString("Leonis");
    if ( code == "LMi" ) return QString("Leonis Minoris");
    if ( code == "Lep" ) return QString("Leporis");
    if ( code == "Lib" ) return QString("Librae");
    if ( code == "Lup" ) return QString("Lupi");
    if ( code == "Lyn" ) return QString("Lyncis");
    if ( code == "Lyr" ) return QString("Lyrae");
    if ( code == "Men" ) return QString("Mensae");
    if ( code == "Mic" ) return QString("Microscopii");
    if ( code == "Mon" ) return QString("Monocerotis");
    if ( code == "Mus" ) return QString("Muscae");
    if ( code == "Nor" ) return QString("Normae");
    if ( code == "Oct" ) return QString("Octantis");
    if ( code == "Oph" ) return QString("Ophiuchi");
    if ( code == "Ori" ) return QString("Orionis");
    if ( code == "Pav" ) return QString("Pavonis");
    if ( code == "Peg" ) return QString("Pegasi");
    if ( code == "Per" ) return QString("Persei");
    if ( code == "Phe" ) return QString("Phoenicis");
    if ( code == "Pic" ) return QString("Pictoris");
    if ( code == "Psc" ) return QString("Piscium");
    if ( code == "PsA" ) return QString("Piscis Austrini");
    if ( code == "Pup" ) return QString("Puppis");
    if ( code == "Pyx" ) return QString("Pyxidis");
    if ( code == "Ret" ) return QString("Reticuli");
    if ( code == "Sge" ) return QString("Sagittae");
    if ( code == "Sgr" ) return QString("Sagittarii");
    if ( code == "Sco" ) return QString("Scorpii");
    if ( code == "Scl" ) return QString("Sculptoris");
    if ( code == "Sct" ) return QString("Scuti");
    if ( code == "Ser" ) return QString("Serpentis");
    if ( code == "Sex" ) return QString("Sextantis");
    if ( code == "Tau" ) return QString("Tauri");
    if ( code == "Tel" ) return QString("Telescopii");
    if ( code == "Tri" ) return QString("Trianguli");
    if ( code == "TrA" ) return QString("Trianguli Australis");
    if ( code == "Tuc" ) return QString("Tucanae");
    if ( code == "UMa" ) return QString("Ursae Majoris");
    if ( code == "UMi" ) return QString("Ursae Minoris");
    if ( code == "Vel" ) return QString("Velorum");
    if ( code == "Vir" ) return QString("Virginis");
    if ( code == "Vol" ) return QString("Volantis");
    if ( code == "Vul" ) return QString("Vulpeculae");
    return code;
}

QString constNameFromAbbrev( const QString &code ) {
    if ( code == "And" ) return QString("Andromeda");
    if ( code == "Ant" ) return QString("Antlia");
    if ( code == "Aps" ) return QString("Apus");
    if ( code == "Aqr" ) return QString("Aquarius");
    if ( code == "Aql" ) return QString("Aquila");
    if ( code == "Ara" ) return QString("Ara");
    if ( code == "Ari" ) return QString("Aries");
    if ( code == "Aur" ) return QString("Auriga");
    if ( code == "Boo" ) return QString("Bootes");
    if ( code == "Cae" ) return QString("Caelum");
    if ( code == "Cam" ) return QString("Camelopardalis");
    if ( code == "Cnc" ) return QString("Cancer");
    if ( code == "CVn" ) return QString("Canes Venatici");
    if ( code == "CMa" ) return QString("Canis Major");
    if ( code == "CMi" ) return QString("Canis Minor");
    if ( code == "Cap" ) return QString("Capricornus");
    if ( code == "Car" ) return QString("Carina");
    if ( code == "Cas" ) return QString("Cassiopeia");
    if ( code == "Cen" ) return QString("Centaurus");
    if ( code == "Cep" ) return QString("Cepheus");
    if ( code == "Cet" ) return QString("Cetus");
    if ( code == "Cha" ) return QString("Chamaeleon");
    if ( code == "Cir" ) return QString("Circinus");
    if ( code == "Col" ) return QString("Columba");
    if ( code == "Com" ) return QString("Coma Berenices");
    if ( code == "CrA" ) return QString("Corona Australis");
    if ( code == "CrB" ) return QString("Corona Borealis");
    if ( code == "Crv" ) return QString("Corvus");
    if ( code == "Crt" ) return QString("Crater");
    if ( code == "Cru" ) return QString("Crux");
    if ( code == "Cyg" ) return QString("Cygnus");
    if ( code == "Del" ) return QString("Delphinus");
    if ( code == "Dor" ) return QString("Doradus");
    if ( code == "Dra" ) return QString("Draco");
    if ( code == "Equ" ) return QString("Equuleus");
    if ( code == "Eri" ) return QString("Eridanus");
    if ( code == "For" ) return QString("Fornax");
    if ( code == "Gem" ) return QString("Gemini");
    if ( code == "Gru" ) return QString("Grus");
    if ( code == "Her" ) return QString("Hercules");
    if ( code == "Hor" ) return QString("Horologium");
    if ( code == "Hya" ) return QString("Hydra");
    if ( code == "Hyi" ) return QString("Hydrus");
    if ( code == "Ind" ) return QString("Indus");
    if ( code == "Lac" ) return QString("Lacerta");
    if ( code == "Leo" ) return QString("Leo");
    if ( code == "LMi" ) return QString("Leo Minor");
    if ( code == "Lep" ) return QString("Lepus");
    if ( code == "Lib" ) return QString("Libra");
    if ( code == "Lup" ) return QString("Lupus");
    if ( code == "Lyn" ) return QString("Lynx");
    if ( code == "Lyr" ) return QString("Lyra");
    if ( code == "Men" ) return QString("Mensa");
    if ( code == "Mic" ) return QString("Microscopium");
    if ( code == "Mon" ) return QString("Monoceros");
    if ( code == "Mus" ) return QString("Musca");
    if ( code == "Nor" ) return QString("Norma");
    if ( code == "Oct" ) return QString("Octans");
    if ( code == "Oph" ) return QString("Ophiuchus");
    if ( code == "Ori" ) return QString("Orion");
    if ( code == "Pav" ) return QString("Pavo");
    if ( code == "Peg" ) return QString("Pegasus");
    if ( code == "Per" ) return QString("Perseus");
    if ( code == "Phe" ) return QString("Phoenix");
    if ( code == "Pic" ) return QString("Pictor");
    if ( code == "Psc" ) return QString("Pisces");
    if ( code == "PsA" ) return QString("Piscis Austrinus");
    if ( code == "Pup" ) return QString("Puppis");
    if ( code == "Pyx" ) return QString("Pyxis");
    if ( code == "Ret" ) return QString("Reticulum");
    if ( code == "Sge" ) return QString("Sagitta");
    if ( code == "Sgr" ) return QString("Sagittarius");
    if ( code == "Sco" ) return QString("Scorpius");
    if ( code == "Scl" ) return QString("Sculptor");
    if ( code == "Sct" ) return QString("Scutum");
    if ( code == "Ser" ) return QString("Serpens");
    if ( code == "Sex" ) return QString("Sextans");
    if ( code == "Tau" ) return QString("Taurus");
    if ( code == "Tel" ) return QString("Telescopium");
    if ( code == "Tri" ) return QString("Triangulum");
    if ( code == "TrA" ) return QString("Triangulum Australe");
    if ( code == "Tuc" ) return QString("Tucana");
    if ( code == "UMa" ) return QString("Ursa Major");
    if ( code == "UMi" ) return QString("Ursa Minor");
    if ( code == "Vel" ) return QString("Vela");
    if ( code == "Vir" ) return QString("Virgo");
    if ( code == "Vol" ) return QString("Volans");
    if ( code == "Vul" ) return QString("Vulpecula");
    return code;
}

QString constNameToAbbrev( const QString &fullName_ ) {
    QString fullName = fullName_.toLower();
    if ( fullName == "andromeda" ) return QString( "And" );
    if ( fullName == "antlia" ) return QString( "Ant" );
    if ( fullName == "apus" ) return QString( "Aps" );
    if ( fullName == "aquarius" ) return QString( "Aqr" );
    if ( fullName == "aquila" ) return QString( "Aql" );
    if ( fullName == "ara" ) return QString( "Ara" );
    if ( fullName == "aries" ) return QString( "Ari" );
    if ( fullName == "auriga" ) return QString( "Aur" );
    if ( fullName == "bootes" ) return QString( "Boo" );
    if ( fullName == "caelum" ) return QString( "Cae" );
    if ( fullName == "camelopardalis" ) return QString( "Cam" );
    if ( fullName == "cancer" ) return QString( "Cnc" );
    if ( fullName == "canes venatici" ) return QString( "CVn" );
    if ( fullName == "canis major" ) return QString( "CMa" );
    if ( fullName == "canis minor" ) return QString( "CMi" );
    if ( fullName == "capricornus" ) return QString( "Cap" );
    if ( fullName == "carina" ) return QString( "Car" );
    if ( fullName == "cassiopeia" ) return QString( "Cas" );
    if ( fullName == "centaurus" ) return QString( "Cen" );
    if ( fullName == "cepheus" ) return QString( "Cep" );
    if ( fullName == "cetus" ) return QString( "Cet" );
    if ( fullName == "chamaeleon" ) return QString( "Cha" );
    if ( fullName == "circinus" ) return QString( "Cir" );
    if ( fullName == "columba" ) return QString( "Col" );
    if ( fullName == "coma berenices" ) return QString( "Com" );
    if ( fullName == "corona australis" ) return QString( "CrA" );
    if ( fullName == "corona borealis" ) return QString( "CrB" );
    if ( fullName == "corvus" ) return QString( "Crv" );
    if ( fullName == "crater" ) return QString( "Crt" );
    if ( fullName == "crux" ) return QString( "Cru" );
    if ( fullName == "cygnus" ) return QString( "Cyg" );
    if ( fullName == "delphinus" ) return QString( "Del" );
    if ( fullName == "doradus" ) return QString( "Dor" );
    if ( fullName == "draco" ) return QString( "Dra" );
    if ( fullName == "equuleus" ) return QString( "Equ" );
    if ( fullName == "eridanus" ) return QString( "Eri" );
    if ( fullName == "fornax" ) return QString( "For" );
    if ( fullName == "gemini" ) return QString( "Gem" );
    if ( fullName == "grus" ) return QString( "Gru" );
    if ( fullName == "hercules" ) return QString( "Her" );
    if ( fullName == "horologium" ) return QString( "Hor" );
    if ( fullName == "hydra" ) return QString( "Hya" );
    if ( fullName == "hydrus" ) return QString( "Hyi" );
    if ( fullName == "indus" ) return QString( "Ind" );
    if ( fullName == "lacerta" ) return QString( "Lac" );
    if ( fullName == "leo" ) return QString( "Leo" );
    if ( fullName == "leo minor" ) return QString( "LMi" );
    if ( fullName == "lepus" ) return QString( "Lep" );
    if ( fullName == "libra" ) return QString( "Lib" );
    if ( fullName == "lupus" ) return QString( "Lup" );
    if ( fullName == "lynx" ) return QString( "Lyn" );
    if ( fullName == "lyra" ) return QString( "Lyr" );
    if ( fullName == "mensa" ) return QString( "Men" );
    if ( fullName == "microscopium" ) return QString( "Mic" );
    if ( fullName == "monoceros" ) return QString( "Mon" );
    if ( fullName == "musca" ) return QString( "Mus" );
    if ( fullName == "norma" ) return QString( "Nor" );
    if ( fullName == "octans" ) return QString( "Oct" );
    if ( fullName == "ophiuchus" ) return QString( "Oph" );
    if ( fullName == "orion" ) return QString( "Ori" );
    if ( fullName == "pavo" ) return QString( "Pav" );
    if ( fullName == "pegasus" ) return QString( "Peg" );
    if ( fullName == "perseus" ) return QString( "Per" );
    if ( fullName == "phoenix" ) return QString( "Phe" );
    if ( fullName == "pictor" ) return QString( "Pic" );
    if ( fullName == "pisces" ) return QString( "Psc" );
    if ( fullName == "piscis austrinus" ) return QString( "PsA" );
    if ( fullName == "puppis" ) return QString( "Pup" );
    if ( fullName == "pyxis" ) return QString( "Pyx" );
    if ( fullName == "reticulum" ) return QString( "Ret" );
    if ( fullName == "sagitta" ) return QString( "Sge" );
    if ( fullName == "sagittarius" ) return QString( "Sgr" );
    if ( fullName == "scorpius" ) return QString( "Sco" );
    if ( fullName == "sculptor" ) return QString( "Scl" );
    if ( fullName == "scutum" ) return QString( "Sct" );
    if ( fullName == "serpens" ) return QString( "Ser" );
    if ( fullName == "sextans" ) return QString( "Sex" );
    if ( fullName == "taurus" ) return QString( "Tau" );
    if ( fullName == "telescopium" ) return QString( "Tel" );
    if ( fullName == "triangulum" ) return QString( "Tri" );
    if ( fullName == "triangulum australe" ) return QString( "TrA" );
    if ( fullName == "tucana" ) return QString( "Tuc" );
    if ( fullName == "ursa major" ) return QString( "UMa" );
    if ( fullName == "ursa minor" ) return QString( "UMi" );
    if ( fullName == "vela" ) return QString( "Vel" );
    if ( fullName == "virgo" ) return QString( "Vir" );
    if ( fullName == "volans" ) return QString( "Vol" );
    if ( fullName == "vulpecula" ) return QString( "Vul" );
    return fullName_;
}

QString constGenetiveToAbbrev( const QString &genetive_ ) {
    QString genetive = genetive_.toLower();
    if ( genetive == "andromedae" ) return QString("And");
    if ( genetive == "antliae" ) return QString("Ant");
    if ( genetive == "apodis" ) return QString("Aps");
    if ( genetive == "aquarii" ) return QString("Aqr");
    if ( genetive == "aquilae" ) return QString("Aql");
    if ( genetive == "arae" ) return QString("Ara");
    if ( genetive == "arietis" ) return QString("Ari");
    if ( genetive == "aurigae" ) return QString("Aur");
    if ( genetive == "bootis" ) return QString("Boo");
    if ( genetive == "caeli" ) return QString("Cae");
    if ( genetive == "camelopardalis" ) return QString("Cam");
    if ( genetive == "cancri" ) return QString("Cnc");
    if ( genetive == "canum venaticorum" ) return QString("CVn");
    if ( genetive == "canis majoris" ) return QString("CMa");
    if ( genetive == "canis minoris" ) return QString("CMi");
    if ( genetive == "capricorni" ) return QString("Cap");
    if ( genetive == "carinae" ) return QString("Car");
    if ( genetive == "cassiopeiae" ) return QString("Cas");
    if ( genetive == "centauri" ) return QString("Cen");
    if ( genetive == "cephei" ) return QString("Cep");
    if ( genetive == "ceti" ) return QString("Cet");
    if ( genetive == "chamaeleontis" ) return QString("Cha");
    if ( genetive == "circini" ) return QString("Cir");
    if ( genetive == "columbae" ) return QString("Col");
    if ( genetive == "comae berenices" ) return QString("Com");
    if ( genetive == "coronae austrinae" ) return QString("CrA");
    if ( genetive == "coronae borealis" ) return QString("CrB");
    if ( genetive == "corvi" ) return QString("Crv");
    if ( genetive == "crateris" ) return QString("Crt");
    if ( genetive == "crucis" ) return QString("Cru");
    if ( genetive == "cygni" ) return QString("Cyg");
    if ( genetive == "delphini" ) return QString("Del");
    if ( genetive == "doradus" ) return QString("Dor");
    if ( genetive == "draconis" ) return QString("Dra");
    if ( genetive == "equulei" ) return QString("Equ");
    if ( genetive == "eridani" ) return QString("Eri");
    if ( genetive == "fornacis" ) return QString("For");
    if ( genetive == "geminorum" ) return QString("Gem");
    if ( genetive == "gruis" ) return QString("Gru");
    if ( genetive == "herculis" ) return QString("Her");
    if ( genetive == "horologii" ) return QString("Hor");
    if ( genetive == "hydrae" ) return QString("Hya");
    if ( genetive == "hydri" ) return QString("Hyi");
    if ( genetive == "indi" ) return QString("Ind");
    if ( genetive == "lacertae" ) return QString("Lac");
    if ( genetive == "leonis" ) return QString("Leo");
    if ( genetive == "leonis minoris" ) return QString("LMi");
    if ( genetive == "leporis" ) return QString("Lep");
    if ( genetive == "librae" ) return QString("Lib");
    if ( genetive == "lupi" ) return QString("Lup");
    if ( genetive == "lyncis" ) return QString("Lyn");
    if ( genetive == "lyrae" ) return QString("Lyr");
    if ( genetive == "mensae" ) return QString("Men");
    if ( genetive == "microscopii" ) return QString("Mic");
    if ( genetive == "monocerotis" ) return QString("Mon");
    if ( genetive == "muscae" ) return QString("Mus");
    if ( genetive == "normae" ) return QString("Nor");
    if ( genetive == "octantis" ) return QString("Oct");
    if ( genetive == "ophiuchi" ) return QString("Oph");
    if ( genetive == "orionis" ) return QString("Ori");
    if ( genetive == "pavonis" ) return QString("Pav");
    if ( genetive == "pegasi" ) return QString("Peg");
    if ( genetive == "persei" ) return QString("Per");
    if ( genetive == "phoenicis" ) return QString("Phe");
    if ( genetive == "pictoris" ) return QString("Pic");
    if ( genetive == "piscium" ) return QString("Psc");
    if ( genetive == "piscis austrini" ) return QString("PsA");
    if ( genetive == "puppis" ) return QString("Pup");
    if ( genetive == "pyxidis" ) return QString("Pyx");
    if ( genetive == "reticuli" ) return QString("Ret");
    if ( genetive == "sagittae" ) return QString("Sge");
    if ( genetive == "sagittarii" ) return QString("Sgr");
    if ( genetive == "scorpii" ) return QString("Sco");
    if ( genetive == "sculptoris" ) return QString("Scl");
    if ( genetive == "scuti" ) return QString("Sct");
    if ( genetive == "serpentis" ) return QString("Ser");
    if ( genetive == "sextantis" ) return QString("Sex");
    if ( genetive == "tauri" ) return QString("Tau");
    if ( genetive == "telescopii" ) return QString("Tel");
    if ( genetive == "trianguli" ) return QString("Tri");
    if ( genetive == "trianguli australis" ) return QString("TrA");
    if ( genetive == "tucanae" ) return QString("Tuc");
    if ( genetive == "ursae majoris" ) return QString("UMa");
    if ( genetive == "ursae minoris" ) return QString("UMi");
    if ( genetive == "velorum" ) return QString("Vel");
    if ( genetive == "virginis" ) return QString("Vir");
    if ( genetive == "volantis" ) return QString("Vol");
    if ( genetive == "vulpeculae" ) return QString("Vul");
    return genetive_;
}


  QString Logging::_filename;

  void Logging::UseFile(const QString &filename)
  {
    _filename = filename;

    // Clear file contents
    QFile file(filename);
    file.open(QFile::WriteOnly);
    file.close();

    qInstallMessageHandler(File);
  }

  void Logging::File(QtMsgType type, const QMessageLogContext &, const QString &msg)
  {
    QFile file(_filename);
    if(file.open(QFile::Append | QIODevice::Text))
    {
      QTextStream stream(&file);
      Write(stream, type, msg);
    }
  }

  void Logging::UseStdout()
  {
    qInstallMessageHandler(Stdout);
  }

  void Logging::Stdout(QtMsgType type, const QMessageLogContext &, const QString &msg)
  {
    QTextStream stream(stdout, QIODevice::WriteOnly);
    Write(stream, type, msg);
  }

  void Logging::UseStderr()
  {
    qInstallMessageHandler(Stderr);
  }

  void Logging::Stderr(QtMsgType type, const QMessageLogContext &, const QString &msg)
  {
    QTextStream stream(stderr, QIODevice::WriteOnly);
    Write(stream, type, msg);
  }

  void Logging::Write(QTextStream &stream, QtMsgType type, const QString &msg)
  {
    stream << QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzz") << " - ";

    switch(type) {
      case QtDebugMsg:
        stream << "DEBG - ";
        break;
      case QtWarningMsg:
        stream << "WARN - ";
        break;
      case QtCriticalMsg:
        stream << "CRIT - ";
        break;
      case QtFatalMsg:
        stream << "FATL - ";
        break;
      default:
        stream << "UNKN - ";
    }

    stream << msg << endl;
  }

  void Logging::UseDefault()
  {
    qInstallMessageHandler(0);
  }

  void Logging::Disable()
  {
    qInstallMessageHandler(Disabled);
  }

  void Logging::Disabled(QtMsgType, const QMessageLogContext &, const QString &)
  {
  }

}
