/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
 * $Id: color.c,v 1.23 2012/08/25 16:38:29 tvrusso Exp $
 *
 * XASTIR, Amateur Station Tracking and Information Reporting
 * Copyright (C) 1999,2000  Frank Giannandrea
 * Copyright (C) 2000-2012  The Xastir Group
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Look at the README for more information on the program.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif  // HAVE_CONFIG_H

#include "snprintf.h"

#include <stdio.h>
#include <Xm/XmAll.h>

#include "xastir.h"
#include "color.h"
#include "xa_config.h"

// Must be last include file
#include "leak_detection.h"



static color_load color_choice[MAX_COLORS];
static int colors_loaded;
static int rm, gm, bm; // rgb masks
static int rs, gs, bs; // rgb shifts
int visual_depth;





/**********************************************************************************/
/* load color file                                                                */
/* load the colors to be used with Xastir                                         */
/* Return 1 if good 0 if not found or error                                       */
/**********************************************************************************/

int load_color_file(void) {
    FILE *f;
    char temp[40];
    int r,g,b;
    char colorname[50];
    int ok,x;

    xastir_snprintf(temp, sizeof(temp), "config/xastir.rgb");
    colors_loaded=0;
    ok=1;
    f=fopen(get_data_base_dir(temp),"r");
    if (f!=NULL) {
        while (!feof(f) && ok) {
            if (fscanf(f,"%d %d %d %49s",&r,&g,&b,colorname)==4) {
                if (colors_loaded < MAX_COLORS) {
                    for (x=0; x<colors_loaded;x++) {
                        if (strcmp(color_choice[x].colorname,colorname)==0) {
                            ok=0;
                            fprintf(stderr,"Error! Duplicate color found %s\n",colorname);
                        }
                    }
                    if (ok) {
                       
                        xastir_snprintf(color_choice[colors_loaded].colorname,
                            MAX_COLORNAME,
                            "%s",
                            colorname);

// Do we really want to assign to unsigned short int's here?
                        color_choice[colors_loaded].color.red=(unsigned short)(r*257);
                        color_choice[colors_loaded].color.blue=(unsigned short)(b*257);
                        color_choice[colors_loaded].color.green=(unsigned short)(g*257);
                        colors_loaded++;
                    }
                } else {
                    ok=0;
                    fprintf(stderr,"Error! MAX_COLORS has been exceeded\n");
                }
            }
        }
        (void)fclose(f);
    } else {
        ok=0;
        fprintf(stderr,"Error! can not find color file: %s\n", get_data_base_dir(temp));
    }
    return(ok);
}





/**********************************************************************************/
/* GetPixelbyName                                                                 */
/* get color for the named choice                                                 */
/* return the pixel data                                                          */
/**********************************************************************************/

Pixel GetPixelByName( Widget w, char *colorname) {
    Display *dpy = XtDisplay(w);
    int scr = DefaultScreen(dpy);
    char warning[200];
    int i,found;

    found=-1;
    i=0;

    do {
        if (strcmp(color_choice[i].colorname, colorname)==0)
            found=i;

        i++;
    } while (i<colors_loaded && found <0);

    if (found >= 0) {

        // XFreeColors() here generates an error.  Why?
        // "BadAccess (attempt to access private resource denied)"
        // XFreeColors(dpy, cmap, &(color_choice[found].color.pixel),1,0);

        if (XAllocColor(dpy,cmap,&color_choice[found].color)) {
            return(color_choice[found].color.pixel);
        }
        else {
            xastir_snprintf(warning, sizeof(warning), "Couldn't allocate color %s", colorname);
            XtWarning(warning);
            return(BlackPixel(dpy,scr));
        }
    }
    else {
        xastir_snprintf(warning, sizeof(warning), "Couldn't find color %s", colorname);
        XtWarning(warning);
        return(BlackPixel(dpy,scr));
    }
}





void setup_visual_info(Display* dpy, int scr) {
    int visuals_matched, i, j;
    XVisualInfo *visual_list, *vp;
    XVisualInfo visual_template;
    rm = gm = bm = rs = gs = bs = 0;

    visual_list = XGetVisualInfo(dpy, VisualNoMask, &visual_template, &visuals_matched);
    if (visuals_matched) {
        if (debug_level & 16)
            fprintf(stderr,"Found %d visuals\n", visuals_matched);

        for (i = 0; i < visuals_matched; i++) {
            vp = &visual_list[i];

            if (vp->visualid == XVisualIDFromVisual(DefaultVisual(dpy, scr))) {
                if (vp->class == TrueColor ||
                    vp->class == DirectColor) {
                    if (vp->red_mask   == 0xf800 &&
                        vp->green_mask == 0x07e0 &&
                        vp->blue_mask  == 0x001f)
                        visual_type = RGB_565;
                    else if (vp->red_mask   == 0x7c00 &&
                             vp->green_mask == 0x03e0 &&
                             vp->blue_mask  == 0x001f)
                        visual_type = RGB_555;
                    else if (vp->red_mask   == 0xff0000 &&
                             vp->green_mask == 0x00ff00 &&
                             vp->blue_mask  == 0x0000ff)
                        visual_type = RGB_888;
                    else {
                        rm = vp->red_mask;
                        gm = vp->green_mask;
                        bm = vp->blue_mask;
                        for (j = 31; j >= 0; j--) {
                            if (rm >= (1 << j)) {
                                rs = j - 15;
                                break;
                            }
                        }
                        for (j = 31; j >= 0; j--) {
                            if (gm >= (1 << j)) {
                                gs = j - 15;
                                break;
                            }
                        }
                        for (j = 31; j >= 0; j--) {
                            if (bm >= (1 << j)) {
                                bs = j - 15;
                                break;
                            }
                        }
                        visual_type = RGB_OTHER;
                    }
                }
                else
                    visual_type = NOT_TRUE_NOR_DIRECT;
                if (debug_level & 16)
                    fprintf(stderr,"\tID:           0x%lx,  Default\n", vp->visualid);
            }
            else if (debug_level & 16)
                fprintf(stderr,"\tID:           0x%lx\n", vp->visualid);
    
            // Store color depth for use by other routines.
            visual_depth = vp->depth;

            if (debug_level & 16) {
                fprintf(stderr,"\tScreen:       %d\n",  vp->screen);
                fprintf(stderr,"\tDepth:        %d\n",  vp->depth);
                fprintf(stderr,"\tClass:        %d",    vp->class);
                switch (vp->class) {
                case StaticGray:
                    fprintf(stderr,",  StaticGray\n");
                    break;
                case GrayScale:
                    fprintf(stderr,",  GrayScale\n");
                    break;
                case StaticColor:
                    fprintf(stderr,",  StaticColor\n");
                    break;
                case PseudoColor:
                    fprintf(stderr,",  PseudoColor\n");
                    break;
                case TrueColor:
                    fprintf(stderr,",  TrueColor\n");
                    break;
                case DirectColor:
                    fprintf(stderr,",  DirectColor\n");
                    break;
                default:
                    fprintf(stderr,",  ??\n");
                    break;
                }
                fprintf(stderr,"\tClrmap Size:  %d\n", vp->colormap_size);
                fprintf(stderr,"\tBits per RGB: %d\n", vp->bits_per_rgb);
                fprintf(stderr,"\tRed Mask:     0x%lx\n",   vp->red_mask);
                fprintf(stderr,"\tGreen Mask:   0x%lx\n",   vp->green_mask);
                fprintf(stderr,"\tBlue Mask:    0x%lx\n\n", vp->blue_mask);
            }
        }
    }
    XFree(visual_list);
}





void pack_pixel_bits(unsigned short r, unsigned short g, unsigned short b, unsigned long* pixel)
{
    switch (visual_type) {
    case RGB_565:
        *pixel = (( r       & 0xf800) |
                  ((g >> 5) & 0x07e0) |
                   (b >> 11));
        break;
    case RGB_555:
        *pixel = (((r >> 1) & 0x7c00) |
                  ((g >> 6) & 0x03e0) |
                   (b >> 11));
        break;
    case RGB_888:
        *pixel = (((r << 8) & 0xff0000) |
                  ( g       & 0x00ff00) |
                   (b >> 8));
        break;
    case RGB_OTHER:
        if (rs >= 0)
            *pixel = ((r << rs) & rm);
        else
            *pixel = ((r >> (-rs)) & rm);
        if (gs >= 0)
            *pixel |= ((g << gs) & gm);
        else
            *pixel |= ((g >> (-gs)) & gm);
        if (bs >= 0)
            *pixel |= ((b << bs) & bm);
        else
            *pixel |= ((b >> (-bs)) & bm);
        break;
    case NOT_TRUE_NOR_DIRECT:
    default:
        break;
    }
}


