#include "Diagram.h"

#include <math.h>

#include "AlphaField.h"
#include "Border.h"
#include "Font.h"
#include "Image.h"
#include "MouseEvent.h"
#include "Scroll.h"
#include "Text.h"
#include "ToolTip.h"

using namespace Framework;

// Contents of the LineDiagram class from Diagram.h
// Constructor
LiveLineDiagram::LiveLineDiagram()
    : DrawableBackground(),
      gF(0xFF000000),
      lColor(new Array<int>()),
      lName(new RCArray<Text>()),
      ph(new RCArray<Array<int>>()),
      pb(new RCArray<Array<int>>()),
      lastValue(new Array<int>()),
      textRd(0),
      gitterGr(0, 0),
      lines(0)
{
    style = 0;
}

// Destructor
LiveLineDiagram::~LiveLineDiagram()
{
    lColor->release();
    lName->release();
    ph->release();
    pb->release();
    lastValue->release();
    if (textRd) textRd->release();
}

// non-constant
void LiveLineDiagram::setTextRendererZ(TextRenderer* textRd)
{
    if (this->textRd) this->textRd->release();
    this->textRd = textRd;
}

void LiveLineDiagram::setFontZ(Font* font) // sets the font
{
    if (!this->textRd)
        textRd = new TextRenderer(font);
    else
        textRd->setFontZ(font);
    rend = 1;
}

void LiveLineDiagram::setGSize(Point& gr) // sets the grid size
{
    gitterGr = gr;
    rend = 1;
}

void LiveLineDiagram::setGColor(int f) // sets the grid color
{
    gF = f;
    rend = 1;
}

void LiveLineDiagram::addLine(const char* name) // adds a line
{
    addLine(new Text(name));
    rend = 1;
}

void LiveLineDiagram::addLine(Text* txt)
{
    lColor->add(0xFFFFFFFF, lines);
    lName->add(txt, lines);
    ph->add(new Array<int>(), lines);
    pb->add(new Array<int>(), lines);
    int rbr = border && hasStyle(Style::Border) ? border->getRWidth() : 0;
    pb->z(lines)->set(gr.x - rbr * 2, 0);
    ++lines;
    rend = 1;
}

void LiveLineDiagram::setLColor(int lNum, int f) // sets the line color
{
    lColor->set(f, lNum);
    rend = 1;
}

void LiveLineDiagram::addPoint(int lNum, int x, int h) // adds a point
{
    Array<int>* ph_tmp = ph->z(lNum);
    Array<int>* pb_tmp = pb->z(lNum);
    if (ph_tmp && pb_tmp)
    {
        int i = pb_tmp->get(0);
        i -= x;
        if (i >= 0) pb_tmp->set(i, 0);
        while (i < 0)
        {
            ph_tmp->remove(0);
            pb_tmp->remove(0);
            if (!pb_tmp->getEntryCount() || !ph_tmp->getEntryCount()) break;
            int ii = -i;
            i = pb_tmp->get(0);
            i -= ii;
            pb_tmp->set(i, 0);
        }
        pb_tmp->add(x);
        ph_tmp->add(h);
        lastValue->set(h, lNum);
    }
    rend = 1;
}

void LiveLineDiagram::removeLine(int lNum) // removes a line
{
    lColor->remove(lNum);
    lName->remove(lNum);
    ph->remove(lNum);
    pb->remove(lNum);
    --lines;
    rend = 1;
}

void LiveLineDiagram::render(Image& zRObj) // draws to zRObj
{
    if (hasStyle(Style::Visible))
    {
        rwLock.lockRead();
        removeStyle(Style::VScroll | Style::HScroll);
        DrawableBackground::render(zRObj);
        if (!zRObj.setDrawOptions(innenPosition, innenSize))
        {
            rwLock.unlockRead();
            return;
        }
        int hv = getHighestValue();
        hv = hv ? hv : 1;
        double yFaktor = innenSize.y / hv;
        if (hasStyle(Style::Gitter))
        {
            double ghi = gitterGr.y * yFaktor;
            int yo = innenSize.y - 1;
            int bo = innenSize.x, ho = innenSize.y;
            int maxBr = (int)((double)innenSize.x / gitterGr.x + 0.5);
            int maxHi = ghi ? (int)(innenSize.y / ghi + 0.5) : 0;
            if (hasStyle(Style::BAlpha))
            {
                for (int i = 0; i < maxBr; ++i)
                    zRObj.drawLineVAlpha(gitterGr.x * i, 0, ho, gF);
                for (int i = 0; i < maxHi; ++i)
                    zRObj.drawLineHAlpha(0, (int)(yo - ghi * i + 0.5), bo, gF);
            }
            else
            {
                for (int i = 0; i < maxBr; ++i)
                    zRObj.drawLineV(gitterGr.x * i, 0, ho, gF);
                for (int i = 0; i < maxHi; ++i)
                    zRObj.drawLineH(0, (int)(yo - ghi * i + 0.5), bo, gF);
            }
        }
        for (int i = 0; i < lines; ++i)
        {
            int f_tmp = lColor->has(i) ? lColor->get(i) : 0;
            Text* n_tmp = lName->z(i);
            Array<int>* ph_tmp = ph->z(i);
            Array<int>* pb_tmp = pb->z(i);
            if (hasStyle(Style::LineName) && textRd && n_tmp)
            {
                textRd->setFontSize(12);
                Text rtxt = n_tmp->getText();
                rtxt += ": ";
                rtxt += lastValue->get(i);
                textRd->renderText(5, 5 + 15 * i, rtxt, zRObj, f_tmp);
            }
            if (ph_tmp && pb_tmp)
            {
                int lastX = 0;
                int lastY = innenSize.y - 1;
                int ph_anz = ph_tmp->getEntryCount();
                int pb_anz = pb_tmp->getEntryCount();
                for (int ii = 0; ii < ph_anz && ii < pb_anz; ++ii)
                {
                    if (!ph_tmp || !pb_tmp) break;
                    int xpos = lastX + pb_tmp->get(ii);
                    int ypos = innenSize.y
                             - (int)(ph_tmp->get(ii) * yFaktor + 0.5) - 1;
                    if (ypos == -1) ++ypos;
                    if (ypos < 0 || xpos < 0) break;
                    if (hasStyle(Style::BAlpha))
                        zRObj.drawLineAlpha(
                            Point(lastX, lastY), Point(xpos, ypos), f_tmp);
                    else
                        zRObj.drawLine(
                            Point(lastX, lastY), Point(xpos, ypos), f_tmp);
                    lastX = xpos;
                    lastY = ypos;
                }
            }
        }
        zRObj.releaseDrawOptions();
        rwLock.unlockRead();
    }
}

// constant
Font* LiveLineDiagram::getFont() const // returns the font
{
    if (textRd) return textRd->getFont();
    return 0;
}

Font* LiveLineDiagram::zFont() const
{
    return textRd ? textRd->zFont() : 0;
}

const Point& LiveLineDiagram::getGSize() const // returns the grid size
{
    return gitterGr;
}

int LiveLineDiagram::getGColor() const // returns the grid color
{
    return gF;
}

int LiveLineDiagram::getLineNumber(
    const char* name) const // returns the line number
{
    for (int i = 0; i < lines; ++i)
    {
        if (lName->z(i)->isEqual(name)) return i;
    }
    return -1;
}

int LiveLineDiagram::getLineNumber(Text* name) const
{
    for (int i = 0; i < lines; ++i)
    {
        if (lName->z(i)->isEqual(name->getText()))
        {
            name->release();
            return i;
        }
    }
    name->release();
    return -1;
}

Text* LiveLineDiagram::getLineName(int lNum) const // returns the line name
{
    return lName->get(lNum);
}

Text* LiveLineDiagram::zLineNames(int lNum) const
{
    return lName->z(lNum);
}

int LiveLineDiagram::getHighestValue() const // returns the highest value
{
    int ret = 0;
    for (int i = 0; i < lines; ++i)
    {
        int tmp = getHighestValue(i);
        ret = ret >= tmp ? ret : tmp;
    }
    return ret;
}

int LiveLineDiagram::getHighestValue(int lNum) const
{
    int ret = 0;
    Array<int>* tmp = ph->z(lNum);
    int anz = tmp->getEntryCount();
    for (int i = 0; i < anz; ++i)
        ret = ret >= tmp->get(i) ? ret : tmp->get(i);
    return ret;
}

int LiveLineDiagram::getMedian(int lNum) const // returns the average value
{
    int count;
    int all = 0;
    Array<int>* tmp = ph->z(lNum);
    int anz = tmp->getEntryCount();
    for (count = 1; count <= anz; ++count)
        all += tmp->get(count - 1);
    return (int)((double)all / count + 0.5);
}

int LiveLineDiagram::getLCount() const // returns the number of lines
{
    return lines;
}

int LiveLineDiagram::getLastValue(int lNum) const // returns the last value
{
    return lastValue->get(lNum);
}

// Contents of the DiagramValue struct from Diagram.h
// Constructor
DiagramValue::DiagramValue()
    : ReferenceCounter(),
      style(0),
      color(0xFFFFFFFF),
      background(0),
      name(new Text()),
      punkte(new Array<DiagramPoint*>)
{}

// Destructor
DiagramValue::~DiagramValue()
{
    name->release();
    int anz = punkte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (punkte->has(i)) delete punkte->get(i);
    }
    punkte->release();
}

// Contents of the DiagramData struct from Diagram.h
// Constructor
DiagramData::DiagramData()
    : ReferenceCounter(),
      style(0),
      rasterDicke(0),
      gridWidth(0),
      rasterHeight(0),
      rasterColor(0),
      hIntervalColor(0xFFFFFFFF),
      vIntervalColor(0xFFFFFFFF),
      hIntervalName(new Text()),
      vIntervalName(new Text()),
      hIntervalTexte(new RCArray<Text>),
      vIntervalTexte(new RCArray<Text>),
      hIntervalWerte(new Array<double>),
      vIntervalWerte(new Array<double>),
      hIntervalWidth(0),
      vIntervalHeight(0),
      werte(new RCArray<DiagramValue>())
{}

// Destructor
DiagramData::~DiagramData()
{
    hIntervalName->release();
    vIntervalName->release();
    hIntervalWerte->release();
    vIntervalWerte->release();
    hIntervalTexte->release();
    vIntervalTexte->release();
    werte->release();
}

// Contents of the BaseDiagram class from Diagram.h
// Constructor
BaseDiagram::BaseDiagram(ReadWriteLock* lock)
    : daten(new DiagramData()),
      changed(0),
      lock(lock)
{}

// Destructor
BaseDiagram::~BaseDiagram()
{
    if (daten) daten->release();
}

// non-constant
void BaseDiagram::setDiagramDataZ(
    DiagramData* dd) // Sets a pointer to the diagram data
{
    lock->lockWrite();
    if (daten) daten->release();
    daten = dd;
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::setDiagramData(DiagramData* dd) // copies the diagram data
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    daten->style = dd->style;
    daten->gridWidth = dd->gridWidth;
    daten->rasterHeight = dd->rasterHeight;
    daten->rasterColor = dd->rasterColor;
    daten->hIntervalColor = dd->hIntervalColor;
    daten->vIntervalColor = dd->vIntervalColor;
    daten->hIntervalName->setText(*dd->hIntervalName);
    daten->vIntervalName->setText(*dd->vIntervalName);
    int anz = dd->hIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (dd->hIntervalWerte->has(i))
            daten->hIntervalWerte->set(dd->hIntervalWerte->get(i), i);
    }
    anz = dd->vIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (dd->vIntervalWerte->has(i))
            daten->vIntervalWerte->set(dd->vIntervalWerte->get(i), i);
    }
    daten->hIntervalWidth = dd->hIntervalWidth;
    daten->vIntervalHeight = dd->vIntervalHeight;
    anz = dd->werte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        DiagramValue* tmp = dd->werte->z(i);
        if (tmp)
        {
            DiagramValue* w = new DiagramValue();
            w->style = tmp->style;
            w->color = tmp->color;
            w->background = tmp->background;
            w->name->setText(tmp->name->getText());
            int anz = tmp->punkte->getEntryCount();
            for (int j = 0; j < anz; ++j)
            {
                if (tmp->punkte->has(j))
                {
                    DiagramPoint* p = new DiagramPoint();
                    p->hInterval = tmp->punkte->get(j)->hInterval;
                    p->vInterval = tmp->punkte->get(j)->vInterval;
                    w->punkte->set(p, j);
                }
            }
            daten->werte->set(w, i);
        }
    }
    dd->release();
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::setGridThickness(int d) // set raster thickness
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->rasterDicke != d) changed = 1;
    daten->rasterDicke = d;
    lock->unlockWrite();
}

void BaseDiagram::setGridWidth(int br) // set raster width
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->gridWidth != br) changed = 1;
    daten->gridWidth = br;
    lock->unlockWrite();
}

void BaseDiagram::setGridHeight(int hi) // set raster height
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->rasterHeight != hi) changed = 1;
    daten->rasterHeight = hi;
    lock->unlockWrite();
}

void BaseDiagram::setGridColor(int f) // set raster color
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->rasterColor != f) changed = 1;
    daten->rasterColor = f;
    lock->unlockWrite();
}

void BaseDiagram::setHIntervalWidth(double br) // interval width
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    daten->hIntervalWidth = br;
    lock->unlockWrite();
}

void BaseDiagram::setVIntervalHeight(double hi) // interval height
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    daten->vIntervalHeight = hi;
    lock->unlockWrite();
}

void BaseDiagram::setHIntervalColor(int f) // color of the horizontal interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->hIntervalColor != f) changed = 1;
    daten->hIntervalColor = f;
    lock->unlockWrite();
}

void BaseDiagram::setVIntervalColor(int f) // color of the vertical interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (daten->vIntervalColor != f) changed = 1;
    daten->vIntervalColor = f;
    lock->unlockWrite();
}

void BaseDiagram::setHIntervalName(
    const char* name) // Sets the name of the horizontal interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->hIntervalName) daten->hIntervalName = new Text();
    if (!daten->hIntervalName->isEqual(name)) changed = 1;
    daten->hIntervalName->setText(name);
    lock->unlockWrite();
}

void BaseDiagram::setHIntervalName(Text* name)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->hIntervalName) daten->hIntervalName = new Text();
    if (!daten->hIntervalName->isEqual(*name)) changed = 1;
    daten->hIntervalName->setText(*name);
    name->release();
    lock->unlockWrite();
}

void BaseDiagram::setVIntervalName(
    const char* name) // Sets the name of the vertical interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->vIntervalName) daten->vIntervalName = new Text();
    if (!daten->vIntervalName->isEqual(name)) changed = 1;
    daten->vIntervalName->setText(name);
    lock->unlockWrite();
}

void BaseDiagram::setVIntervalName(Text* name)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->vIntervalName) daten->vIntervalName = new Text();
    if (!daten->vIntervalName->isEqual(*name)) changed = 1;
    daten->vIntervalName->setText(*name);
    name->release();
    lock->unlockWrite();
}

void BaseDiagram::addHIntervalText(double hInterval,
    const char* text) // Add text for a horizontal interval
{
    setHIntervalText(hInterval, text);
}

void BaseDiagram::addHIntervalText(double hInterval, Text* text)
{
    setHIntervalText(hInterval, *text);
    text->release();
}

void BaseDiagram::setHIntervalTextZ(double hInterval,
    Text* text) // Sets the text of a horizontal interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->hIntervalWerte) daten->hIntervalWerte = new Array<double>();
    if (!daten->hIntervalTexte) daten->hIntervalTexte = new RCArray<Text>();
    int anz = daten->hIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->hIntervalWerte->has(i)
            && daten->hIntervalWerte->get(i) == hInterval)
        {
            daten->hIntervalTexte->set(text, i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    daten->hIntervalWerte->set(hInterval, anz);
    daten->hIntervalTexte->set(text, anz);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::setHIntervalText(double hInterval, Text* text)
{
    setHIntervalText(hInterval, *text);
    text->release();
}

void BaseDiagram::setHIntervalText(double hInterval, const char* text)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->hIntervalWerte) daten->hIntervalWerte = new Array<double>();
    if (!daten->hIntervalTexte) daten->hIntervalTexte = new RCArray<Text>();
    int anz = daten->hIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->hIntervalWerte->has(i)
            && daten->hIntervalWerte->get(i) == hInterval)
        {
            if (!daten->hIntervalTexte->z(i))
                daten->hIntervalTexte->set(new Text(text), i);
            else
                daten->hIntervalTexte->z(i)->setText(text);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    daten->hIntervalWerte->set(hInterval, anz);
    daten->hIntervalTexte->set(new Text(text), anz);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::removeHIntervalText(
    double hInterval) // removes the text of a horizontal interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->hIntervalWerte) daten->hIntervalWerte = new Array<double>();
    if (!daten->hIntervalTexte) daten->hIntervalTexte = new RCArray<Text>();
    int anz = daten->hIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->hIntervalWerte->has(i)
            && daten->hIntervalWerte->get(i) == hInterval)
        {
            daten->hIntervalTexte->remove(i);
            daten->hIntervalWerte->remove(i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    lock->unlockWrite();
}

void BaseDiagram::addVIntervalText(double vInterval,
    const char* text) // Add text for a vertical interval
{
    setVIntervalText(vInterval, text);
}

void BaseDiagram::addVIntervalText(double vInterval, Text* text)
{
    setVIntervalText(vInterval, *text);
    text->release();
}

void BaseDiagram::setVIntervalTextZ(
    double vInterval, Text* text) // Sets the text of a vertical interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->vIntervalWerte) daten->vIntervalWerte = new Array<double>();
    if (!daten->vIntervalTexte) daten->vIntervalTexte = new RCArray<Text>();
    int anz = daten->vIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->vIntervalWerte->has(i)
            && daten->vIntervalWerte->get(i) == vInterval)
        {
            daten->vIntervalTexte->set(text, i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    daten->vIntervalWerte->set(vInterval, anz);
    daten->vIntervalTexte->set(text, anz);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::setVIntervalText(double vInterval, Text* text)
{
    setVIntervalText(vInterval, *text);
    text->release();
}

void BaseDiagram::setVIntervalText(double vInterval, const char* text)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->vIntervalWerte) daten->vIntervalWerte = new Array<double>();
    if (!daten->vIntervalTexte) daten->vIntervalTexte = new RCArray<Text>();
    int anz = daten->vIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->vIntervalWerte->has(i)
            && daten->vIntervalWerte->get(i) == vInterval)
        {
            if (!daten->vIntervalTexte->z(i))
                daten->vIntervalTexte->set(new Text(text), i);
            else
                daten->vIntervalTexte->z(i)->setText(text);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    daten->vIntervalWerte->set(vInterval, anz);
    daten->vIntervalTexte->set(new Text(text), anz);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::removeVIntervalText(
    double vInterval) // removes the text of a vertical interval
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->vIntervalWerte) daten->vIntervalWerte = new Array<double>();
    if (!daten->vIntervalTexte) daten->vIntervalTexte = new RCArray<Text>();
    int anz = daten->vIntervalWerte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->vIntervalWerte->has(i)
            && daten->vIntervalWerte->get(i) == vInterval)
        {
            daten->vIntervalTexte->remove(i);
            daten->vIntervalWerte->remove(i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    lock->unlockWrite();
}

void BaseDiagram::addValueZ(DiagramValue* w) // Adds a value
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    daten->werte->add(w);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addValue(DiagramValue* w)
{
    lock->lockWrite();
    DiagramValue* tmp = new DiagramValue();
    tmp->style = w->style;
    tmp->color = w->color;
    tmp->background = w->background;
    tmp->name->setText(*w->name);
    int anz = w->punkte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (w->punkte->has(i))
        {
            DiagramPoint* p = new DiagramPoint();
            p->hInterval = w->punkte->get(i)->hInterval;
            p->vInterval = w->punkte->get(i)->vInterval;
            tmp->punkte->set(p, i);
        }
    }
    w->release();
    addValueZ(tmp);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addValue(const char* name)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    DiagramValue* w = new DiagramValue();
    w->name->setText(name);
    daten->werte->add(w);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addValue(Text* txt)
{
    addValue(*txt);
    txt->release();
}

void BaseDiagram::setValueColor(int wNum, int f) // sets the color of a value
{
    if (wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    daten->werte->z(wNum)->color = f;
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addPointZ(
    int wNum, DiagramPoint* p) // adds a point to a value
{
    if (wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    while (!daten->werte->has(wNum))
        daten->werte->add(new DiagramValue());
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    daten->werte->z(wNum)->punkte->add(p);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addPoint(int wNum, DiagramPoint* p)
{
    if (wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    while (!daten->werte->has(wNum))
        daten->werte->add(new DiagramValue());
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    DiagramPoint* tmp = new DiagramPoint();
    tmp->hInterval = p->hInterval;
    tmp->vInterval = p->vInterval;
    daten->werte->z(wNum)->punkte->add(tmp);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::addPoint(int wNum, double hI, double vI)
{
    if (wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    DiagramPoint* tmp = new DiagramPoint();
    tmp->hInterval = hI;
    tmp->vInterval = vI;
    daten->werte->z(wNum)->punkte->add(tmp);
    lock->unlockWrite();
    changed = 1;
}

// changes an existing point
void BaseDiagram::setPointZ(int wNum, double hI, DiagramPoint* p)
{
    setPointZ(wNum, getDiagramPointPos(wNum, hI), p);
}

void BaseDiagram::setPoint(int wNum, double hI, DiagramPoint* p)
{
    setPoint(wNum, getDiagramPointPos(wNum, hI), p->hInterval, p->vInterval);
}

void BaseDiagram::setPoint(int wNum, double hI, double h, double v)
{
    setPoint(wNum, getDiagramPointPos(wNum, hI), h, v);
}

void BaseDiagram::setPointZ(int wNum, int pNum, DiagramPoint* p)
{
    if (pNum < 0 || wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    if (daten->werte->z(wNum)->punkte->has(pNum))
        delete daten->werte->z(wNum)->punkte->get(pNum);
    daten->werte->z(wNum)->punkte->set(p, pNum);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::setPoint(int wNum, int pNum, DiagramPoint* p)
{
    if (pNum < 0 || wNum < 0) return;
    setPoint(wNum, pNum, p->hInterval, p->vInterval);
}

void BaseDiagram::setPoint(int wNum, int pNum, double h, double v)
{
    if (pNum < 0 || wNum < 0) return;
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    if (!daten->werte->z(wNum)->punkte->has(pNum))
        daten->werte->z(wNum)->punkte->set(new DiagramPoint(), pNum);
    daten->werte->z(wNum)->punkte->get(pNum)->hInterval = h;
    daten->werte->z(wNum)->punkte->get(pNum)->vInterval = v;
    lock->unlockWrite();
    changed = 1;
}

// Deletes an existing point
void BaseDiagram::removePoint(int wNum, double hI)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    int anz = daten->werte->z(wNum)->punkte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->werte->z(wNum)->punkte->has(i)
            && daten->werte->z(wNum)->punkte->get(i)->hInterval == hI)
        {
            delete daten->werte->z(wNum)->punkte->get(i);
            daten->werte->z(wNum)->punkte->remove(i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    lock->unlockWrite();
}

void BaseDiagram::removePoint(int wNum, int pNum)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (!daten->werte->z(wNum)->punkte)
        daten->werte->z(wNum)->punkte = new Array<DiagramPoint*>();
    if (daten->werte->z(wNum)->punkte->has(pNum))
    {
        delete daten->werte->z(wNum)->punkte->get(pNum);
        daten->werte->z(wNum)->punkte->remove(pNum);
        changed = 1;
    }
    lock->unlockWrite();
}

void BaseDiagram::removeValue(int wNum) // removes a value
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    daten->werte->remove(wNum);
    lock->unlockWrite();
    changed = 1;
}

void BaseDiagram::removeValue(const char* name)
{
    lock->lockWrite();
    if (!daten) daten = new DiagramData();
    if (!daten->werte) daten->werte = new RCArray<DiagramValue>();
    int anz = daten->werte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        DiagramValue* tmp = daten->werte->z(i);
        if (tmp && tmp->name && tmp->name->isEqual(name))
        {
            daten->werte->remove(i);
            lock->unlockWrite();
            changed = 1;
            return;
        }
    }
    lock->unlockWrite();
}

void BaseDiagram::removeValue(Text* name)
{
    removeValue(name->getText());
    name->release();
}

void BaseDiagram::addDataStyle(int style) // Sets the style of the data
{
    if (!daten) daten = new DiagramData();
    if ((daten->style | style) != daten->style) changed = 1;
    daten->style |= style;
}

void BaseDiagram::setDataStyle(int style)
{
    if (!daten) daten = new DiagramData();
    if (daten->style != style) changed = 1;
    daten->style = style;
}

void BaseDiagram::setDataStyle(int style, bool addRemove)
{
    if (addRemove)
        addDataStyle(style);
    else
        removeDataStyle(style);
}

void BaseDiagram::removeDataStyle(int style)
{
    if (!daten) daten = new DiagramData();
    if ((daten->style & ~style) != daten->style) changed = 1;
    daten->style &= ~style;
}

void BaseDiagram::addValueStyle(
    int wNum, int style) // Sets the style of a value
{
    if (wNum < 0) return;
    if (!daten) daten = new DiagramData();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if ((daten->werte->z(wNum)->style | style) != daten->werte->z(wNum)->style)
        changed = 1;
    daten->werte->z(wNum)->style |= style;
}

void BaseDiagram::setValueStyle(int wNum, int style)
{
    if (wNum < 0) return;
    if (!daten) daten = new DiagramData();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if (daten->werte->z(wNum)->style != style) changed = 1;
    daten->werte->z(wNum)->style = style;
}

void BaseDiagram::setValueStyle(int wNum, int style, bool addRemove)
{
    if (wNum < 0) return;
    if (addRemove)
        addValueStyle(wNum, style);
    else
        removeValueStyle(wNum, style);
}

void BaseDiagram::removeValueStyle(int wNum, int style)
{
    if (wNum < 0) return;
    if (!daten) daten = new DiagramData();
    if (!daten->werte->z(wNum)) daten->werte->set(new DiagramValue(), wNum);
    if ((daten->werte->z(wNum)->style & ~style) != daten->werte->z(wNum)->style)
        changed = 1;
    daten->werte->z(wNum)->style &= ~style;
}

// constant
DiagramData* BaseDiagram::getDiagramData() const // Returns the diagram data
{
    return daten ? dynamic_cast<DiagramData*>(daten->getThis()) : 0;
}

DiagramData* BaseDiagram::zDiagramData() const
{
    return daten;
}

DiagramValue* BaseDiagram::getDiagramValue(
    int wNum) const // Returns the data of a value
{
    return (daten && daten->werte) ? daten->werte->get(wNum) : 0;
}

DiagramValue* BaseDiagram::zDiagramValue(int wNum) const
{
    return (daten && daten->werte) ? daten->werte->z(wNum) : 0;
}

DiagramValue* BaseDiagram::getDiagramValue(const char* name) const
{
    return getDiagramValue(getDiagramValuePos(name));
}

DiagramValue* BaseDiagram::zDiagramValue(const char* name) const
{
    return zDiagramValue(getDiagramValuePos(name));
}

int BaseDiagram::getDiagramValuePos(
    const char* name) const // Returns the position of a value
{
    if (!daten || !daten->werte) return -1;
    int anz = daten->werte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->werte->z(i) && daten->werte->z(i)->name
            && daten->werte->z(i)->name->isEqual(name))
            return i;
    }
    return -1;
}

int BaseDiagram::getDiagramPointPos(int wNum,
    double hI) const // Returns the position of a point from a value
{
    if (!daten || !daten->werte || !daten->werte->z(wNum)
        || !daten->werte->z(wNum)->punkte)
        return -1;
    int anz = daten->werte->z(wNum)->punkte->getEntryCount();
    for (int i = 0; i < anz; ++i)
    {
        if (daten->werte->z(wNum)->punkte->has(i)
            && daten->werte->z(wNum)->punkte->get(i)->hInterval == hI)
            return i;
    }
    return -1;
}

int BaseDiagram::getDiagramPointPos(char* wName, double hI) const
{
    return getDiagramPointPos(getDiagramValuePos(wName), hI);
}

bool BaseDiagram::hasDataStyle(int style) const // Checks the style of the data
{
    if (!daten) return 0;
    return (daten->style | style) == daten->style;
}

bool BaseDiagram::hasDataStyleNot(int style) const
{
    if (!daten) return 1;
    return (daten->style | style) != daten->style;
}

bool BaseDiagram::hasValueStyle(
    int wNum, int style) const // Checks the style of a value
{
    if (!daten || !daten->werte || !daten->werte->z(wNum)) return 0;
    return (daten->werte->z(wNum)->style | style)
        == daten->werte->z(wNum)->style;
}

bool BaseDiagram::hasValueStyleNot(int wNum, int style) const
{
    if (!daten || !daten->werte || !daten->werte->z(wNum)) return 1;
    return (daten->werte->z(wNum)->style | style)
        != daten->werte->z(wNum)->style;
}

// Contents of the BarDiagram class from Diagram.h
// Constructor
LineDiagram::LineDiagram()
    : DrawableBackground(),
      BaseDiagram(&rwLock),
      textRd(0),
      dRam(new LBorder()),
      dBgF(0),
      dBgB(0),
      dAf(new AlphaField()),
      vIntervalRB(new Image()),
      hIntervalRB(new Image()),
      fontGr(12)
{
    style = 0;
    vertikalScrollBar = new VScrollBar();
    horizontalScrollBar = new HScrollBar();
}

// Destructor
LineDiagram::~LineDiagram()
{
    if (textRd) textRd->release();
    if (dRam) dRam->release();
    if (dBgB) dBgB->release();
    if (dAf) dAf->release();
    if (vIntervalRB) vIntervalRB->release();
    if (hIntervalRB) hIntervalRB->release();
}

void LineDiagram::doMouseEvent(MouseEvent& me, bool userRet)
{
    if (hasDataStyle(DiagramData::Style::Visible)
        && (hasStyle(Style::HScroll) || hasStyle(Style::VScroll)) && userRet)
    {
        int rbr = 0;
        if (hasStyle(Style::Border) && border) rbr = border->getRWidth();
        bool vs = hasStyle(Style::VScroll) && vertikalScrollBar;
        bool hs = hasStyle(Style::HScroll) && horizontalScrollBar;
        if (vs)
        {
            if (hs)
                horizontalScrollBar->doMouseMessage(
                    rbr, gr.y - rbr - 15, gr.x - rbr * 2 - 15, 15, me);
            vertikalScrollBar->doMouseMessage(
                gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me);
        }
        else if (hs)
            horizontalScrollBar->doMouseMessage(
                rbr, gr.y - rbr - 15, gr.x - rbr * 2, 15, me);
    }
    me.processed = userRet;
}

// non-constant
void LineDiagram::setTextRendererZ(TextRenderer* textRd)
{
    rwLock.lockWrite();
    if (this->textRd) this->textRd->release();
    this->textRd = textRd;
    rwLock.unlockWrite();
}

void LineDiagram::setFontZ(Font* font) // Sets the font
{
    rwLock.lockWrite();
    if (!this->textRd)
        textRd = new TextRenderer(font);
    else
        textRd->setFontZ(font);
    rend = 1;
    rwLock.unlockWrite();
}

void LineDiagram::setFontSize(int gr)
{
    rwLock.lockWrite();
    if (fontGr != gr) rend = 1;
    fontGr = gr;
    rwLock.unlockWrite();
}

void LineDiagram::setDataBorderZ(
    Border* ram) // Sets the inner border around the actual diagram
{
    rwLock.lockWrite();
    if (dRam) dRam->release();
    dRam = ram;
    rwLock.unlockWrite();
    rend = 1;
}

void LineDiagram::setDataBorder(Border* ram)
{
    rwLock.lockWrite();
    if (!dRam) dRam = new LBorder();
    dRam->setAlpha(ram->hasAlpha());
    dRam->setColor(ram->getColor());
    dRam->setBorderWidth(ram->getRWidth());
    rwLock.unlockWrite();
    ram->release();
    rend = 1;
}

void LineDiagram::setDataBorderWidth(int br)
{
    rwLock.lockWrite();
    if (!dRam) dRam = new LBorder();
    if (dRam->getRWidth() != br) rend = 1;
    dRam->setBorderWidth(br);
    rwLock.unlockWrite();
}

void LineDiagram::setDataBorderColor(int f)
{
    rwLock.lockWrite();
    if (!dRam) dRam = new LBorder();
    dRam->setColor(f);
    rwLock.unlockWrite();
    rend = 1;
}

void LineDiagram::setDataBackgroundColor(
    int f) // Sets the background of the actual diagram
{
    dBgF = f;
    rend = 1;
}

void LineDiagram::setDataBackgroundImageZ(Image* b)
{
    rwLock.lockWrite();
    if (dBgB) dBgB->release();
    dBgB = b;
    rwLock.unlockWrite();
    rend = 1;
}

void LineDiagram::setDataBackgroundImage(Image* b)
{
    rwLock.lockWrite();
    if (!dBgB) dBgB = new Image();
    dBgB->newImage(b->getWidth(), b->getHeight(), 0);
    dBgB->drawImage(0, 0, b->getWidth(), b->getHeight(), *b);
    rwLock.unlockWrite();
    b->release();
    rend = 1;
}

void LineDiagram::setDataAlphaFieldZ(
    AlphaField* af) // Sets the AlphaField of the actual diagram
{
    rwLock.lockWrite();
    if (dAf) dAf->release();
    dAf = af;
    rwLock.unlockWrite();
    rend = 1;
}

void LineDiagram::setDataAlphaField(AlphaField* af)
{
    rwLock.lockWrite();
    if (!dAf) dAf = new AlphaField();
    dAf->setColor(af->getColor());
    dAf->setStrength(af->getStrength());
    rwLock.unlockWrite();
    af->release();
    rend = 1;
}

void LineDiagram::setDataAlphaFieldColor(int f)
{
    rwLock.lockWrite();
    if (!dAf) dAf = new AlphaField();
    dAf->setColor(f);
    rwLock.unlockWrite();
    rend = 1;
}

void LineDiagram::setDataAlphaFieldStrength(int st)
{
    rwLock.lockWrite();
    if (!dAf) dAf = new AlphaField();
    if (dAf->getStrength() != st) rend = 1;
    dAf->setStrength(st);
    rwLock.unlockWrite();
}

void LineDiagram::render(Image& zRObj)
{
    if (!hasDataStyle(DiagramData::Style::Visible)) return;
    DrawableBackground::render(zRObj);
    if (!zRObj.setDrawOptions(innenPosition, innenSize)) return;
    rwLock.lockRead();
    int dgy = 0;
    int dgbr = innenSize.x;
    int dghi = innenSize.y;
    int vIAnz = 0;
    int hIAnz = 0;
    if (daten)
    { // calculating auto values
        vIAnz = daten->vIntervalWerte ? daten->vIntervalWerte->getEntryCount()
                                      : 0;
        hIAnz = daten->hIntervalWerte ? daten->hIntervalWerte->getEntryCount()
                                      : 0;
        if (daten->vIntervalWerte
            && hasDataStyle(DiagramData::Style::AutoIntervalHeight))
        {
            double maxW = 0;
            for (int i = 0; i < vIAnz; ++i)
            {
                if (daten->vIntervalWerte->has(i)
                    && daten->vIntervalWerte->get(i) > maxW)
                    maxW = daten->vIntervalWerte->get(i);
            }
            if (vertikalScrollBar && hasStyle(Style::VScroll))
                daten->vIntervalHeight
                    = maxW ? (vertikalScrollBar->getScroll() / maxW) : 0;
            else
                daten->vIntervalHeight
                    = maxW ? (vIntervalRB->getWidth() / maxW) : 0;
        }
        if (hasDataStyle(DiagramData::Style::AutoGridHeight))
            daten->rasterHeight = daten->vIntervalHeight;
        if (daten->hIntervalWerte
            && hasDataStyle(DiagramData::Style::AutoIntervalWidth))
        {
            double maxW = 0;
            for (int i = 0; i < hIAnz; ++i)
            {
                if (daten->hIntervalWerte->has(i)
                    && daten->hIntervalWerte->get(i) > maxW)
                    maxW = daten->hIntervalWerte->get(i);
            }
            if (horizontalScrollBar && hasStyle(Style::HScroll))
                daten->hIntervalWidth
                    = maxW ? (horizontalScrollBar->getScroll() / maxW) : 0;
            else
                daten->hIntervalWidth
                    = maxW ? (hIntervalRB->getWidth() / maxW) : 0;
        }
        if (hasDataStyle(DiagramData::Style::AutoGridWidth))
            daten->gridWidth = daten->hIntervalWidth;
    }
    if (hasDataStyle(DiagramData::Style::VInterval) && textRd && fontGr
        && daten)
    { // rendering of the vertical interval
        int vIRBbr = innenSize.y;
        if (hasDataStyle(DiagramData::Style::HInterval)
            && daten->hIntervalColor)
            vIRBbr -= fontGr + 2;
        if (vIRBbr > 0)
        {
            if (vIntervalRB->getWidth() != vIRBbr
                || vIntervalRB->getHeight() != fontGr + 2)
                vIntervalRB->newImage(vIRBbr, fontGr + 2, 0xFF000000);
            else
                vIntervalRB->fillRegion(0, 0, vIRBbr, fontGr + 2, 0xFF000000);
            textRd->setFontSize(fontGr);
            if (daten->vIntervalWerte)
            {
                int* rf = new int[vIAnz];
                int anz = 0;
                bool* fertig = new bool[vIAnz];
                ZeroMemory(fertig, vIAnz);
                for (int i = 0; i < vIAnz; ++i)
                {
                    double min = 0;
                    int mI = -1;
                    for (int j = 0; j < vIAnz; ++j)
                    {
                        if (!fertig[j] && daten->vIntervalWerte->has(j)
                            && (daten->vIntervalWerte->get(j) < min || mI < 0))
                        {
                            mI = j;
                            min = daten->vIntervalWerte->get(j);
                        }
                    }
                    if (mI < 0) break;
                    rf[anz] = mI;
                    ++anz;
                    fertig[mI] = 1;
                }
                delete[] fertig;
                Text txt;
                int xPos = 0;
                if (vertikalScrollBar && hasStyle(Style::VScroll))
                    xPos -= vertikalScrollBar->getScroll();
                int rWeite = xPos - 10;
                for (int i = anz - 1; i >= 0; --i)
                {
                    txt = "";
                    if (hasDataStyle(DiagramData::Style::VIntervalTexte)
                        && daten->vIntervalTexte
                        && daten->vIntervalTexte->z(rf[i]))
                        txt = daten->vIntervalTexte->z(rf[i])->getText();
                    else if (hasDataStyleNot(DiagramData::Style::VIntervalTexte)
                             || !daten->vIntervalWerte)
                        txt = daten->vIntervalWerte->get(rf[i]);
                    xPos = (int)(daten->vIntervalWerte->get(rf[i])
                                 * daten->vIntervalHeight);
                    xPos = (vertikalScrollBar && hasStyle(Style::VScroll)
                                   ? vertikalScrollBar->getScroll()
                                   : vIntervalRB->getWidth())
                         - xPos;
                    if (vertikalScrollBar && hasStyle(Style::VScroll))
                        xPos -= vertikalScrollBar->getScroll();
                    int br = textRd->getTextWidth(txt);
                    if (xPos + br > vIntervalRB->getWidth()
                        && vIntervalRB->getWidth() - br >= rWeite + 10)
                        xPos = vIntervalRB->getWidth() - br;
                    if (xPos >= rWeite + 10)
                    {
                        textRd->renderText(
                            xPos, 1, txt, *vIntervalRB, daten->vIntervalColor);
                        rWeite = xPos + br + 10;
                    }
                }
                delete[] rf;
            }
            if (daten->vIntervalName)
            {
                int vinbr
                    = textRd->getTextWidth(daten->vIntervalName->getText());
                int vinx = vIntervalRB->getWidth() / 2 - vinbr / 2;
                vIntervalRB->fillRegion(
                    vinx - 5, 1, vinbr + 10, fontGr, 0xFF000000);
                textRd->renderText(vinx,
                    1,
                    daten->vIntervalName->getText(),
                    *vIntervalRB,
                    daten->vIntervalColor);
            }
            if (hasDataStyle(DiagramData::Style::HInterval)
                && daten->hIntervalColor)
                zRObj.alphaImage90(innenSize.x - vIntervalRB->getHeight(),
                    fontGr + 2,
                    vIntervalRB->getWidth(),
                    vIntervalRB->getHeight(),
                    *vIntervalRB);
            else
                zRObj.alphaImage90(innenSize.x - vIntervalRB->getHeight(),
                    0,
                    vIntervalRB->getWidth(),
                    vIntervalRB->getHeight(),
                    *vIntervalRB);
            dgbr -= vIntervalRB->getHeight();
        }
    }
    if (hasDataStyle(DiagramData::Style::HInterval) && textRd && fontGr
        && daten)
    { // rendering of the horizontal interval
        int hIRBbr = innenSize.x;
        if (hasDataStyle(DiagramData::Style::VInterval)
            && daten->vIntervalColor)
            hIRBbr -= fontGr + 2;
        if (hIRBbr > 0)
        {
            if (hIntervalRB->getWidth() != hIRBbr
                || hIntervalRB->getHeight() != fontGr + 2)
                hIntervalRB->newImage(hIRBbr, fontGr + 2, 0xFF000000);
            else
                hIntervalRB->fillRegion(0, 0, hIRBbr, fontGr + 2, 0xFF000000);
            textRd->setFontSize(fontGr);
            if (daten->hIntervalWerte)
            {
                int* rf = new int[hIAnz];
                int anz = 0;
                bool* fertig = new bool[hIAnz];
                ZeroMemory(fertig, hIAnz);
                for (int i = 0; i < hIAnz; ++i)
                {
                    double min = 0;
                    int mI = -1;
                    for (int j = 0; j < hIAnz; ++j)
                    {
                        if (!fertig[j] && daten->hIntervalWerte->has(j)
                            && (daten->hIntervalWerte->get(j) < min || mI < 0))
                        {
                            mI = j;
                            min = daten->hIntervalWerte->get(j);
                        }
                    }
                    if (mI < 0) break;
                    rf[anz] = mI;
                    ++anz;
                    fertig[mI] = 1;
                }
                delete[] fertig;
                Text txt;
                int xPos = 0;
                if (horizontalScrollBar && hasStyle(Style::HScroll))
                    xPos -= horizontalScrollBar->getScroll();
                int rWeite = xPos - 10;
                for (int i = 0; i < anz; ++i)
                {
                    txt = "";
                    if (hasDataStyle(DiagramData::Style::HIntervalTexte)
                        && daten->hIntervalTexte
                        && daten->hIntervalTexte->z(rf[i]))
                        txt = daten->hIntervalTexte->z(rf[i])->getText();
                    else if (hasDataStyleNot(DiagramData::Style::HIntervalTexte)
                             || !daten->hIntervalWerte)
                        txt = daten->hIntervalWerte->get(rf[i]);
                    xPos = (int)(daten->hIntervalWerte->get(rf[i])
                                 * daten->hIntervalWidth);
                    if (horizontalScrollBar && hasStyle(Style::HScroll))
                        xPos -= horizontalScrollBar->getScroll();
                    int br = textRd->getTextWidth(txt);
                    if (xPos + br > hIntervalRB->getWidth()
                        && hIntervalRB->getWidth() - br >= rWeite + 10)
                        xPos = hIntervalRB->getWidth() - br;
                    if (xPos >= rWeite + 10)
                    {
                        textRd->renderText(
                            xPos, 1, txt, *hIntervalRB, daten->hIntervalColor);
                        rWeite = xPos + br + 10;
                    }
                }
                delete[] rf;
            }
            if (daten->hIntervalName)
            {
                int hinbr
                    = textRd->getTextWidth(daten->hIntervalName->getText());
                int hinx = hIntervalRB->getWidth() / 2 - hinbr / 2;
                hIntervalRB->fillRegion(
                    hinx - 5, 1, hinbr + 10, fontGr, 0xFF000000);
                textRd->renderText(hinx,
                    1,
                    daten->hIntervalName->getText(),
                    *hIntervalRB,
                    daten->hIntervalColor);
            }
            zRObj.alphaImage(0,
                0,
                hIntervalRB->getWidth(),
                hIntervalRB->getHeight(),
                *hIntervalRB);
            dghi -= hIntervalRB->getHeight();
            dgy += hIntervalRB->getHeight();
        }
    }
    if (!zRObj.setDrawOptions(0, dgy, dgbr, dghi))
    {
        zRObj.releaseDrawOptions();
        rwLock.unlockRead();
        return;
    }
    dgy = 0;
    int dgrbr = 0;
    if (hasStyle(Style::DataBorder) && dRam)
    {
        dRam->setSize(dgbr, dghi);
        dRam->render(zRObj);
        dgrbr = dRam->getRWidth();
    }
    if (!zRObj.setDrawOptions(dgrbr, dgrbr, dgbr - dgrbr * 2, dghi - dgrbr * 2))
    {
        zRObj.releaseDrawOptions();
        zRObj.releaseDrawOptions();
        rwLock.unlockRead();
        return;
    }
    if (hasStyle(Style::DataBackground))
    {
        if (hasStyle(Style::DataHAlpha))
            zRObj.alphaRegion(0, 0, dgbr - dgrbr * 2, dghi - dgrbr * 2, dBgF);
        else
            zRObj.fillRegion(0, 0, dgbr - dgrbr * 2, dghi - dgrbr * 2, dBgF);
        if (hasStyle(Style::DataHImage) && dBgB)
        {
            if (hasStyle(Style::DataHAlpha))
                zRObj.alphaImage(
                    0, 0, dgbr - dgrbr * 2, dghi - dgrbr * 2, *dBgB);
            else
                zRObj.drawImage(
                    0, 0, dgbr - dgrbr * 2, dghi - dgrbr * 2, *dBgB);
        }
    }
    if (hasStyle(Style::DataBuffered) && dAf)
    {
        dAf->setSize(dgbr - dgrbr * 2, dghi - dgrbr * 2);
        dAf->render(zRObj);
    }
    if (hasDataStyle(DiagramData::Style::Raster) && daten && daten->rasterDicke
        && daten->gridWidth && daten->rasterHeight)
    { // Raster
        int maxBr = dgbr;
        if (horizontalScrollBar && hasStyle(Style::HScroll))
            maxBr = horizontalScrollBar->getScroll();
        int maxHi = dghi;
        if (vertikalScrollBar && hasStyle(Style::VScroll))
            maxHi = vertikalScrollBar->getScroll();
        for (double x = horizontalScrollBar && hasStyle(Style::HScroll)
                          ? -horizontalScrollBar->getScroll()
                          : 0;
            x < maxBr;
            x += daten->gridWidth)
        {
            for (int i = 0; i < daten->rasterDicke; ++i)
            {
                if (hasDataStyle(DiagramData::Style::RasterAlpha))
                    zRObj.drawLineVAlpha((int)(x + i),
                        dgy + dgrbr,
                        dghi - dgrbr * 2,
                        daten->rasterColor);
                else
                    zRObj.drawLineV((int)(x + i),
                        dgy + dgrbr,
                        dghi - dgrbr * 2,
                        daten->rasterColor);
            }
        }
        for (double y = maxHi;
            y > (vertikalScrollBar && hasStyle(Style::VScroll)
                     ? -vertikalScrollBar->getScroll()
                     : 0);
            y -= daten->rasterHeight)
        {
            for (int i = 0; i < daten->rasterDicke; ++i)
            {
                if (hasDataStyle(DiagramData::Style::RasterAlpha))
                    zRObj.drawLineHAlpha(
                        0, (int)(y + i), dgbr - dgrbr * 2, daten->rasterColor);
                else
                    zRObj.drawLineH(
                        0, (int)(y + i), dgbr - dgrbr * 2, daten->rasterColor);
            }
        }
    }
    if (daten && daten->werte && daten->werte->getEntryCount()
        && daten->hIntervalWidth && daten->vIntervalHeight)
    { // values
        int wAnz = daten->werte->getEntryCount();
        for (int i = 0; i < wAnz; ++i)
        {
            DiagramValue* wert = daten->werte->z(i);
            if (wert && hasValueStyle(i, DiagramValue::Style::Visible)
                && wert->punkte && wert->punkte->getEntryCount())
            {
                int pAnz = wert->punkte->getEntryCount();
                int* rf = new int[pAnz];
                bool* fertig = new bool[pAnz];
                int anz = 0;
                ZeroMemory(fertig, pAnz);
                for (int j = 0; j < pAnz; ++j)
                {
                    double min = -1;
                    int p = -1;
                    for (int pi = 0; pi < pAnz; ++pi)
                    {
                        if (wert->punkte->has(pi) && !fertig[pi]
                            && (p < 0
                                || wert->punkte->get(pi)->hInterval < min))
                        {
                            min = wert->punkte->get(pi)->hInterval;
                            p = pi;
                        }
                    }
                    if (p < 0) break;
                    rf[anz] = p;
                    fertig[p] = 1;
                    ++anz;
                }
                delete[] fertig;
                int rpx = horizontalScrollBar && hasStyle(Style::HScroll)
                            ? -horizontalScrollBar->getScroll()
                            : 0;
                int rpy = vertikalScrollBar && hasStyle(Style::VScroll)
                            ? -vertikalScrollBar->getScroll()
                            : 0;
                rpy += dgy;
                int dgmhi
                    = vertikalScrollBar && hasStyle(Style::VScroll)
                        ? dgy + vertikalScrollBar->getScrollData()->max + dgrbr
                        : dgy + dghi - dgrbr;
                if (hasValueStyle(i, DiagramValue::Style::Background))
                {
                    DiagramPoint* vorher = 0;
                    DiagramPoint* jetzt = 0;
                    for (int j = 0; j < anz; ++j)
                    {
                        jetzt = wert->punkte->get(rf[j]);
                        if (jetzt && vorher)
                        {
                            int ax = (int)(rpx
                                           + vorher->hInterval
                                                 * daten->hIntervalWidth);
                            int ay = (int)(dgmhi
                                           - vorher->vInterval
                                                 * daten->vIntervalHeight);
                            int bx = (int)(rpx
                                           + jetzt->hInterval
                                                 * daten->hIntervalWidth);
                            int by = (int)(dgmhi
                                           - jetzt->vInterval
                                                 * daten->vIntervalHeight);
                            if (ax >= bx)
                            {
                                vorher = jetzt;
                                continue;
                            }
                            if (!(ax > dgbr - dgrbr || bx < 0
                                    || (ay > dgy + dghi - dgrbr
                                        && by > dgy + dghi - dgrbr)))
                            {
                                double yf = (double)(by - ay) / (bx - ax);
                                double y = (double)ay;
                                ax = ax < 0 ? 0 : ax;
                                bx = bx > dgbr - dgrbr ? dgbr - dgrbr : bx;
                                if (hasValueStyle(
                                        i, DiagramValue::Style::HAlpha))
                                {
                                    for (int x = ax; x < bx; x++, y += yf)
                                        zRObj.drawLineVAlpha(x,
                                            (int)(y + 0.5),
                                            dgmhi - (int)(y + 0.5),
                                            wert->background);
                                }
                                else
                                {
                                    for (int x = ax; x < bx; x++, y += yf)
                                        zRObj.drawLineV(x,
                                            (int)(y + 0.5),
                                            dgmhi - (int)(y + 0.5),
                                            wert->background);
                                }
                                if (hasValueStyle(
                                        i, DiagramValue::Style::Alpha))
                                    zRObj.drawLineAlpha(Point(ax, ay),
                                        Point(bx, by),
                                        wert->color);
                                else
                                    zRObj.drawLine(Point(ax, ay),
                                        Point(bx, by),
                                        wert->color);
                            }
                        }
                        vorher = jetzt;
                    }
                }
                else
                {
                    DiagramPoint* vorher = 0;
                    DiagramPoint* jetzt = 0;
                    for (int j = 0; j < anz; ++j)
                    {
                        jetzt = wert->punkte->get(rf[j]);
                        if (jetzt && vorher)
                        {
                            if (hasValueStyle(i, DiagramValue::Style::Alpha))
                                zRObj.drawLineAlpha(
                                    Point((int)(rpx
                                                + vorher->hInterval
                                                      * daten->hIntervalWidth),
                                        (int)(dgmhi
                                              - vorher->vInterval
                                                    * daten->vIntervalHeight)),
                                    Point((int)(rpx
                                                + jetzt->hInterval
                                                      * daten->hIntervalWidth),
                                        (int)(dgmhi
                                              - jetzt->vInterval
                                                    * daten->vIntervalHeight)),
                                    wert->color);
                            else
                                zRObj.drawLine(
                                    Point((int)(rpx
                                                + vorher->hInterval
                                                      * daten->hIntervalWidth),
                                        (int)(dgmhi
                                              - vorher->vInterval
                                                    * daten->vIntervalHeight)),
                                    Point((int)(rpx
                                                + jetzt->hInterval
                                                      * daten->hIntervalWidth),
                                        (int)(dgmhi
                                              - jetzt->vInterval
                                                    * daten->vIntervalHeight)),
                                    wert->color);
                        }
                        vorher = jetzt;
                    }
                }
                delete[] rf;
            }
        }
    }
    if (daten && daten->werte && daten->werte->getEntryCount() && textRd
        && fontGr)
    {
        int wAnz = daten->werte->getEntryCount();
        int rx = 5;
        int ry = 5;
        textRd->setFontSize(fontGr);
        for (int i = 0; i < wAnz; ++i)
        {
            DiagramValue* w = daten->werte->z(i);
            if (w && w->name && hasValueStyle(i, DiagramValue::Style::Name)
                && hasValueStyle(i, DiagramValue::Style::Visible))
            {
                int br = textRd->getTextWidth(w->name->getText());
                zRObj.alphaRegion(rx, ry, br, fontGr, 0xA0000000);
                textRd->renderText(rx, ry, w->name->getText(), zRObj, w->color);
                ry += 15;
            }
        }
    }
    zRObj.releaseDrawOptions();
    zRObj.releaseDrawOptions();
    zRObj.releaseDrawOptions();
    rwLock.unlockRead();
}

// constant
Font* LineDiagram::getFont() const // Returns the font
{
    return textRd ? textRd->getFont() : 0;
}

Font* LineDiagram::zFont() const
{
    return textRd ? textRd->zFont() : 0;
}

Border* LineDiagram::getDataBorder()
    const // Returns the inner border around the actual diagram
{
    return dRam ? dynamic_cast<Border*>(dRam->getThis()) : 0;
}

Border* LineDiagram::zDataBorder() const
{
    return dRam;
}

int LineDiagram::getDataBorderColor() const
{
    return dRam ? dRam->getColor() : 0;
}

int LineDiagram::getDataBorderWidth() const
{
    return dRam ? dRam->getRWidth() : 0;
}

int LineDiagram::getDataBackgroundColor()
    const // Returns the background of the actual diagram
{
    return dBgF;
}

Image* LineDiagram::getDataBackgroundImage() const
{
    return dBgB ? dynamic_cast<Image*>(dBgB->getThis()) : 0;
}

Image* LineDiagram::zDataBackgroundImage() const
{
    return dBgB;
}

AlphaField* LineDiagram::getDataAlphaField()
    const // Returns the AlphaField of the actual diagram
{
    return dAf ? dynamic_cast<AlphaField*>(dAf->getThis()) : 0;
}

AlphaField* LineDiagram::zDataAlphaField() const
{
    return dAf;
}

int LineDiagram::getDataAlphaFieldColor() const
{
    return dAf ? dAf->getColor() : 0;
}

int LineDiagram::getDataAlphaFieldStrength() const
{
    return dAf ? dAf->getStrength() : 0;
}