//  bbsmount_base.cc for bbsmount - an tool for simple mounting in X11
//
//  Copyright (c) 2001 by Miroslav Jezbera, jezberam@phoenix.inf.upol.cz
//
//  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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// (See the included file COPYING / GPL-2.0)
//

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

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/stat.h>
#include <sys/types.h>
#define __USE_BSD	1
#include <string.h>

#include "bbsmount_base.hh"
#include "bbsmount.hh"

File::File(const char * file_name, const char * images_prefix) {

    path = NULL;
    const_cast<char *>(images_path) = images_prefix;
    FindFile(file_name);
}

File::~File() {
    if (path)
	free(path);
}

bool
File::Exist(void) const {
    return (path != NULL);
}

char *
File::GetPath(void) const {
    return path;
}

void
File::FindFile(const char *file_name) {
    struct stat info;
    char *str, *default_dir;
    int length;

    if (!file_name)
	return;
    if (stat(file_name, &info) == 0) {	// This file is in current directory
	path = strdup(file_name);
	return;
    }
    if (images_path) {
	length = strlen(images_path);
	str = (char *)malloc(sizeof(char) * (length + strlen(file_name) + 2));
	str = strcpy(str, images_path);
	if (str[length - 1] != '/') {
	    str[length + 1] = '\0';
	    str[length] = '/';
	}
	str = strcat(str, file_name);
	if (stat(str, &info) == 0) {	// This file is in image_prefix
	    path = str;
	    return;
	}
	free(str);
    }
    default_dir = IMAGES_DIR;
    length = strlen(default_dir);
    str = (char *)malloc(sizeof(char) * (length + strlen(file_name) + 2));
    sprintf(str, "%s/%s", default_dir, file_name);
    if (stat(str, &info) == 0) {	// This file is in default directory
	path = str;
	return;
    }
    free(str);
}

Action::Action()
{
    command_if_mouted = 0;
    command_if_not_mounted = 0;
    button = 0;
    modifiers = 0;
    nmodifiers = 0;
}

Action::Action(const Action &copy)
{
    command_if_mouted = copy.GetCommand(true);
    command_if_not_mounted = copy.GetCommand(false);
    button = copy.GetButton();
    modifiers = copy.GetModifiers();
    nmodifiers = copy.GetNegativeModifiers();
}

Action::~Action()
{
}

unsigned int
Action::GetCommand(const bool mounted) const
{
    if (mounted)
	return command_if_mouted;
    else
	return command_if_not_mounted;
}

unsigned int
Action::GetButton() const
{
    return button;
}

unsigned int
Action::GetModifiers() const
{
    return modifiers;
}

unsigned int
Action::GetNegativeModifiers() const
{
    return nmodifiers;
}

bool
Action::IsActive(const unsigned int _button, const unsigned int state) const
{
    return (_button == button && (state & modifiers) == modifiers && (state & nmodifiers) == 0);
}

void
Action::SetCommand(const unsigned int command, const bool mounted)
{
    if (mounted) {
	command_if_mouted = command;
	if (!command_if_not_mounted)
	    command_if_not_mounted = command;
    }
    else {
	command_if_not_mounted = command;
	if (!command_if_mouted)
	    command_if_mouted = command;
    }
}

void
Action::SetButton(const unsigned int _button)
{
    button = _button;
}

void
Action::AddModifier(const unsigned int _modifier)
{
    if (!(_modifier & nmodifiers))
	modifiers |= _modifier;
}

void
Action::AddNegativeModifier(const unsigned int _modifier)
{
    if (!(_modifier & modifiers))
	nmodifiers |= _modifier;
}


MountPoint::MountPoint(const string &_mountpoint)
{
    mountpoint = _mountpoint;
    mounted_image = not_mounted_image = mounted_info = not_mounted_info = error_info = 0;
    mounted = false;
    commandlock = false;
    was_error = false;
}

MountPoint::MountPoint(const MountPoint &copy)
{
    mountpoint = copy.GetMountPoint();
    mounted_image = copy.GetMountedImage();
    description = copy.getDescription();
    not_mounted_image = copy.GetNotMountedImage();
    mounted_info = copy.getMountedInfo();
    not_mounted_info = copy.getNotMountedInfo();
    error_info = copy.getErrorInfo();
    mounted = copy.IsMounted();
    actions = copy.GetActions();
    commandlock = false;
    was_error = false;
}

MountPoint::~MountPoint()
{
}

bool
MountPoint::IsMounted() const
{
    return mounted;
}

unsigned int
MountPoint::GetMountedImage() const
{
    return mounted_image;
}

unsigned int
MountPoint::GetNotMountedImage() const
{
    return not_mounted_image;
}

unsigned int
MountPoint::GetCurrentImage(bool &ismounted) const
{
    ismounted = mounted;
    if (ismounted)
	return mounted_image;
    else
	return not_mounted_image;
}

unsigned int
MountPoint::getMountedInfo(void) const
{
    return mounted_info;
}

unsigned int
MountPoint::getNotMountedInfo(void) const
{
    return not_mounted_info;
}

unsigned int
MountPoint::getErrorInfo(void) const
{
    return error_info;
}

unsigned int
MountPoint::getCurrentInfo(void) const
{
    if (was_error)
	return error_info;
    else
	if (mounted)
	    return mounted_info;
	else
	    return not_mounted_info;
}

const string &
MountPoint::GetMountPoint() const
{
    return mountpoint;
}

const string &
MountPoint::getDescription(void) const
{
    return description;
}

const string &
MountPoint::getLastError(void) const
{
    return last_error;
}

const set<Action> &
MountPoint::GetActions() const
{
    return actions;
}

unsigned int
MountPoint::GetCommand(const unsigned int button, const unsigned int state) const
{
    set<Action>::iterator pointer = actions.begin();

    for (; pointer != actions.end(); pointer++)
	if (pointer->IsActive(button, state))
	    return pointer->GetCommand(mounted);
    return 0;
}

bool
MountPoint::IsLocked() const
{
    return commandlock;
}

void
MountPoint::AddAction(const Action &action)
{
    actions.insert(action);
}

void
MountPoint::SetMountedImage(const unsigned int image)
{
    mounted_image = image;
}

void
MountPoint::SetNotMountedImage(const unsigned int image)
{
    not_mounted_image = image;
}

void
MountPoint::setMountedInfo(const unsigned int infotext)
{
    mounted_info = infotext;
}

void
MountPoint::setNotMountedInfo(const unsigned int infotext)
{
    not_mounted_info = infotext;
}

void
MountPoint::setErrorInfo(const unsigned int infotext)
{
    error_info = infotext;
}

void
MountPoint::setDescription(const string &desc)
{
    description = desc;
}

void
MountPoint::setLastError(const string &error)
{
    was_error = true;
    last_error = error;
}

void
MountPoint::clearError(void)
{
    was_error = false;
    last_error.erase();
}

void
MountPoint::SetMounted(const bool is_mounted)
{
    was_error = false;
    mounted = is_mounted;
}

void
MountPoint::Lock()
{
    commandlock = true;
}

void
MountPoint::Unlock()
{
    commandlock = false;
}

MyImage::MyImage(Display *_dpy, const Pixmap image, const Pixmap shape)
{
    normal_pixmap = image;
    shape_pixmap = shape;
    dpy = _dpy;
}

MyImage::MyImage(Display *_dpy, const Window &rootwin, XpmImage *image)
{
    XpmAttributes attrs;
    int result;
    dpy = _dpy;
    attrs.visual = DefaultVisual(dpy, DefaultScreen(dpy));
    attrs.colormap = DefaultColormap(dpy, DefaultScreen(dpy));
    attrs.depth = DefaultDepth(dpy, DefaultScreen(dpy));
    attrs.width = 0;
    attrs.height = 0;
    attrs.x_hotspot = 0;
    attrs.y_hotspot = 0;
    attrs.cpp = 0;
    attrs.pixels = (Pixel *)0;
    attrs.npixels = 0;
    attrs.colorsymbols = (XpmColorSymbol *)0;
    attrs.numsymbols = 0;
    attrs.rgb_fname = NULL;
    attrs.nextensions = 0;
    attrs.extensions = (XpmExtension *)0;
    attrs.closeness = 0;
    attrs.exactColors = True;
    attrs.valuemask = XpmVisual | XpmColormap | XpmDepth | XpmExactColors | XpmCloseness;
    result = XpmCreatePixmapFromXpmImage(dpy, rootwin, image, &normal_pixmap, &shape_pixmap, &attrs);
    switch (result) {
	case XpmColorError:
#if DEBUG
	    if (debug_level >= dbg_warning)
		printf("XpmError: Color substitution was needed.\n");
#endif
	    break;
	case XpmColorFailed:
	    printf("XpmError: Color allocation failed! Insufficient colors available, increase screen depth\n");
	    attrs.exactColors = False;
	    attrs.closeness = 50000;
	    result = XpmCreatePixmapFromXpmImage(dpy, rootwin, image, &normal_pixmap, &shape_pixmap, &attrs);
	    if (result != XpmSuccess && result != XpmColorError)
		printf("XpmError: Dithering failed!\n");
	    else
		printf("Using dithered image.\n");
	    break;
	case XpmNoMemory:
	    printf("XpmError: Not enough memory for XpmImage to Pixmap conversion!\n");
	    break;
	case XpmSuccess:
#if DEBUG
	    if (debug_level >= dbg_all_work)
		printf("Conversion from XpmImage to Pixmap was successful.\n");
#endif
	    break;
    }
    XpmFreeAttributes(&attrs);
}

MyImage::MyImage(const MyImage &copy)
{
    normal_pixmap = copy.GetImage();
    shape_pixmap = copy.GetImageShape();
    dpy = AppWindow->getXDisplay();
}

MyImage::~MyImage()
{
    XFreePixmap(dpy, normal_pixmap);
    XFreePixmap(dpy, shape_pixmap);
}

Display *
MyImage::GetDisplay()
{
    return dpy;
}

Pixmap
MyImage::GetImage(void) const
{
    return normal_pixmap;
}

Pixmap
MyImage::GetImageShape(void) const
{
    return shape_pixmap;
}

MountWindow::MountWindow(MountPoint *_mountpoint, Display *_display, const Window _parent, const int _x, const int _y, const unsigned int _width, const unsigned int _height)
{
    unsigned long create_mask;
    XSetWindowAttributes attribs;
    XGCValues values;
    
    mountpoint = _mountpoint;
    display = _display;
    parent = _parent;
    x = _x;
    y = _y;
    width = _width;
    height = _height;
    drawmounted = false;
    create_mask = CWBackPixmap | CWEventMask;
    attribs.background_pixmap = AppWindow->GetPixmaps().draw;
    raised = true;
//    attribs.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask;
    attribs.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask;
    mywindow = XCreateWindow(display, parent, x, y, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, create_mask, &attribs);
    mywindowgc = XCreateGC(display, mywindow, 0L, &values);
}

MountWindow::~MountWindow()
{
    XFreeGC(display, mywindowgc);
    XDestroyWindow(display, mywindow);
}

const Window
MountWindow::GetWindow() const
{
    return mywindow;
}

MountPoint &
MountWindow::GetMountPoint(void)
{
    return (*mountpoint);
}

void
MountWindow::Update(void)
{
    bool ismounted;

    mountpoint->GetCurrentImage(ismounted);
    if (ismounted != drawmounted)
	Draw();
}

void
MountWindow::SetPressed(const bool is_pressed)
{
    if (is_pressed == raised)
	Draw(!is_pressed);
}

void
MountWindow::Draw(const bool _raised)
{
    XGCValues values;
    int imageidx;

    if (raised != _raised) {
	raised = _raised;
	XSetWindowBackgroundPixmap(display, mywindow, (raised ? AppWindow->GetPixmaps().draw : AppWindow->GetPixmaps().draw_pressed));
    }
    imageidx = mountpoint->GetCurrentImage(drawmounted);
    values.clip_mask = AppWindow->GetImage(imageidx).GetImageShape();
    XClearWindow(display, mywindow);
    XChangeGC(display, mywindowgc, GCClipMask, &values);
    XCopyArea(display, AppWindow->GetImage(imageidx).GetImage(), mywindow, mywindowgc, 0, 0, width, height, 0, 0);
}

void
MountWindow::Draw(const int _x, const int _y, const unsigned int _width, const unsigned int _height)
{
    bool ismounted;
    int imageidx;

    imageidx = mountpoint->GetCurrentImage(ismounted);
    if (ismounted != drawmounted)
	Draw();
    else {
	XClearArea(display, mywindow, _x, _y, _width, _height, False);
	XCopyArea(display, AppWindow->GetImage(imageidx).GetImage(), mywindow, mywindowgc, _x, _y, _width, _height, _x, _y);
    }
}

void
MountWindow::Resize(const unsigned int _width, const unsigned int _height)
{
    width = _width;
    height = _height;
    XResizeWindow(display, mywindow, width, height);
}

void
MountWindow::Move(const int _x, const int _y)
{
    x = _x;
    y = _y;
    XMoveWindow(display, mywindow, x, y);
}

void
MountWindow::MoveResize(const int _x, const int _y, const unsigned int _width, const unsigned int _height)
{
    x = _x;
    y = _y;
    width = _width;
    height = _height;
    XMoveResizeWindow(display, mywindow, x, y, width, height);
}



syntax highlighted by Code2HTML, v. 0.9.1