#KanDeLa.
#Copyright (C) 2011 Alain Barbason
#
#This file is part of KanDeLa.
#
#KanDeLa 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 3 of the License, or
#(at your option) any later version.
#
#KanDeLa 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 KanDeLa.  If not, see <http://www.gnu.org/licenses/>.
#
use strict;
use warnings;
use vars qw($width_line $drawing $view);
$width_line=3;    # epaisseur des lignes
$drawing="";      # surface de dssin
$view="technique";
package Line;
use Commun;
our @ISA=qw( Commun );
use Math::Trig;
use Data::Dumper;
our %liste;
our %created;
sub getListe {
    my $self=shift;
    return %liste;
}
sub find {
    my $o_id=shift;
    my $oa=shift;
    my $e_id=shift;
    my $ea=shift;
    return ($created{$o_id}{$oa}{$e_id}{$ea});
}
sub forSelect {
    foreach my $liste (values %liste) {
        if ($liste->select) {
            $liste->configure(@_);
            $liste->redraw;
        }
    }
}
sub new {
    my $classe=shift;
    my $self=$classe->SUPER::new();
    my %param=@_;
    if ($param{"-id"}) {
        $self->{ID}=$param{"-id"};
        Commun::set_id($self->{ID});
    }
    if (defined($param{"-oi"}))
    { # rewrite param is oi,oj,ei,ej OR o,e for security more test is necessary
        my $pin_o=Epingle::find($param{"-oi"}, $param{"-oj"});
        my $pin_e=Epingle::find($param{"-ei"}, $param{"-ej"});
        delete($param{"-oi"});
        delete($param{"-oj"});
        delete($param{"-ei"});
        delete($param{"-ej"});
        $param{"-ido"}=$pin_o->id;
        $param{"-ide"}=$pin_e->id;
    }
    $self->{O}=$Epingle::liste{$param{"-ido"}};
    $self->{O}->incO();
    $self->{E}=$Epingle::liste{$param{"-ide"}};
    $self->{E}->incE();
    $self->{OA}=$param{"-oa"};
    $self->{EA}=$param{"-ea"};
    $self->{SEG}=defined($param{"-seg"})   ? $param{"-seg"}  : "0.5";
    $self->{SEG2}=defined($param{"-seg2"}) ? $param{"-seg2"} : "0.5";
    $self->{COULEUR}=$param{"-couleur"} || $param{"-col2"} || "purple";
    $self->{TORDRE}=$param{"-tordre"} || 0.5;
    $self->{NBRE_TORDRE}=$param{"-nbre_tordre"} || 0;
    $self->{TD}="";    # id of tk for twist mark
    $self->{TD2}="";
    $self->{TD3}="";
    $self->{PIQUE}=$param{"-pique"};
    $self->{WIDTH}=3;
    $self->{OD}="";    # reference à l'id du dessin
    $self->{ED}="";    # reference à l'id du dessin
    $self->{SELECT}=0;
    bless($self, $classe);
    #print Dumper $self;
    $self->draw();
    $liste{$self->id}=$self;
    $created{$self->o->id}{$self->oa}{$self->e->id}{$self->ea}=$self;
    $self->undoDelete;
    return $self;
}
#sub duplicate {
# todo
#}
sub configure {    # todo put this sub in Commun.pm
    my $self=shift;
    my %param=@_;    # rewrite use %param
    foreach my $key (keys %param) {    # todo check for multiple parameter
        my $newKey=uc(substr($key, 1));
        $self->{$newKey}=$param{$key};
    }
}
sub o {
    my $self=shift;
    if (@_) {$self->{O}=shift}
    return $self->{O};
}
sub e {
    my $self=shift;
    if (@_) {$self->{E}=shift}
    return $self->{E};
}
sub oa {
    my $self=shift;
    if (@_) {$self->{OA}=shift}
    $self->redraw;
    return $self->{OA};
}
sub ea {
    my $self=shift;
    if (@_) {$self->{EA}=shift}
    $self->redraw;
    return $self->{EA};
}
sub min_i {
    my $self=shift;
    if   ($self->o->i < $self->e->i) {return $self->o->i;}
    else                             {return $self->e->i;}
}
sub min_j {
    my $self=shift;
    if   ($self->o->j < $self->e->j) {return $self->o->j;}
    else                             {return $self->e->j;}
}
sub max_i {
    my $self=shift;
    if   ($self->o->i > $self->e->i) {return $self->o->i;}
    else                             {return $self->e->i;}
}
sub max_j {
    my $self=shift;
    if   ($self->o->j > $self->e->j) {return $self->o->j;}
    else                             {return $self->e->j;}
}
sub di {
    # vecteur de la ligne
    my $self=shift;
    return $self->e->i-$self->o->i;
}
sub dj {
    my $self=shift;
    return $self->e->j-$self->o->j;
}
sub seg {
    my $self=shift;
    if (@_) {$self->{SEG}=shift}
    return $self->{SEG};
}
sub seg2 {
    my $self=shift;
    if (@_) {
        $self->{SEG2}=shift;
        $self->redraw;
    }
    return $self->{SEG2};
}
sub select {
    my $self=shift;
    return $self->{SELECT};
}
sub pique {
    my $self=shift;
    return $self->{PIQUE};
}
sub tordre {
    my $self=shift;
    if (@_) {
        $self->{TORDRE}=shift;
        $self->redraw;
    }
    return $self->{TORDRE};
}
sub nbre_tordre {
    my $self=shift;
    if (@_) {$self->{NBRE_TORDRE}=shift}
    if ($self->{NBRE_TORDRE} > 3) {$self->{NBRE_TORDRE}=0}
    return $self->{NBRE_TORDRE};
}
sub color {
    my $self=shift;
    return $self->couleur(@_);
}
sub couleur {
    my $self=shift;
    if (@_) {
        $self->{COULEUR}=shift;
        $self->redraw;
    }
    return $self->{COULEUR};
}
sub inLozenge {
    my $self=shift;
    return Commun->inLozenge($self->o->j, $self->o->i, @_)
      && Commun->inLozenge($self->e->j, $self->e->i, @_);
}
sub draw {
    my $self=shift;
    $self->redraw(@_);
}
sub segment {
    my $self=shift;
    my ($trait, $x1, $y1, $x2, $y2)=@_;
    if (!$self->{$trait}) {
        $self->{$trait}=$::drawing->createLine(
            $x1, $y1, $x2, $y2,
            -fill  => "red",
            -width => $::width_line,
            -tags  => ["id=$self->{ID}", "seg"]
        );
        $::liste{$self->{$trait}}=$self;
    }
    else {
        $::drawing->coords($self->{$trait}, $x1, $y1, $x2, $y2);
    }
}
sub segments {
    my $self=shift;
    my ($xo, $yo, $xe, $ye)=@_;
    $::drawing->itemconfigure($self->{TD},  -state => "hidden");
    $::drawing->itemconfigure($self->{TD2}, -state => "hidden");
    $::drawing->itemconfigure($self->{TD3}, -state => "hidden");
    # rewrite mieux fixer les problèmes de segments vert et horiz
    if ($ye==$yo) {
        $ye=$yo+1;
    }
    if ($xe==$xo) {
        $xe=$xo+1;
    }
    if (($self->{NBRE_TORDRE} >= 1) && ($ye != $yo) && ($xe != $xo)) {
        my $xt=$xo*$self->{TORDRE}+$xe*(1-$self->{TORDRE});
        my $yt=$yo*$self->{TORDRE}+$ye*(1-$self->{TORDRE});
        my $r2=25;
        # cooef directeur de la droite
        my $b=($ye-$yo)/($xe-$xo);
        my $b2=$b*$b;
        my $b2p1=$b2+1;
        # cooef directeur de du segment trodre
        my $a=-($xe-$xo)/($ye-$yo);
        my $a2=$a*$a;
        my $a2p1=$a2+1;
        my $x1=$xt+sqrt($r2/$a2p1);
        my $y1=$yt+$a*sqrt($r2/$a2p1);
        my $x2=$xt-sqrt($r2/$a2p1);
        my $y2=$yt-$a*sqrt($r2/$a2p1);
        $self->segment("TD", $x1, $y1, $x2, $y2);

        if ($Commun::view_technique) {
            $::drawing->itemconfigure($self->{TD}, -state => "normal");
        }
        if ($self->{NBRE_TORDRE} >= 2) {
            my $xtt=$xt+sqrt($r2/$b2p1);
            my $ytt=$yt+$b*sqrt($r2/$b2p1);
            my $x1=$xtt+sqrt($r2/$a2p1);
            my $y1=$ytt+$a*sqrt($r2/$a2p1);
            my $x2=$xtt-sqrt($r2/$a2p1);
            my $y2=$ytt-$a*sqrt($r2/$a2p1);
            $self->segment("TD2", $x1, $y1, $x2, $y2);
            if ($Commun::view_technique) {
                $::drawing->itemconfigure($self->{TD2}, -state => "normal");
            }
        }
        if ($self->{NBRE_TORDRE} >= 3) {
            my $xtt=$xt-sqrt($r2/$b2p1);
            my $ytt=$yt-$b*sqrt($r2/$b2p1);
            my $x1=$xtt+sqrt($r2/$a2p1);
            my $y1=$ytt+$a*sqrt($r2/$a2p1);
            my $x2=$xtt-sqrt($r2/$a2p1);
            my $y2=$ytt-$a*sqrt($r2/$a2p1);
            $self->segment("TD3", $x1, $y1, $x2, $y2);
            if ($Commun::view_technique) {
                $::drawing->itemconfigure($self->{TD3}, -state => "normal");
            }
        }
    }
}
sub cdLine {
    # crée ou redessine une ligne
    my $self=shift;
    my ($seg, $xo, $yo, $xe, $ye, $color, $width)=@_;
    if ($self->{$seg}) {
        $::drawing->coords($self->{$seg}, $xo, $yo, $xe, $ye);
        $::drawing->itemconfigure(
            $self->{$seg},
            -fill  => $color,
            -width => $width
        );
    }
    else {
        $self->{$seg}=$::drawing->createLine(
            $xo, $yo, $xe, $ye,
            -fill  => $color,
            -width => $width,
            -tags  => ["id=$self->{ID}", $seg],
            #           -arrowshape => [5,15,8],         # fleche directionnel
            #	    -arrow => "last"
        );
        $::liste{$self->{$seg}}=$self;
    }
}
sub normal {
    my $self=shift;
    $::drawing->itemconfigure($self->{OD},  -state => "normal");
    $::drawing->itemconfigure($self->{ED},  -state => "normal");
    $::drawing->itemconfigure($self->{MD},  -state => "normal");
    $::drawing->itemconfigure($self->{TD},  -state => "normal");
    $::drawing->itemconfigure($self->{TD2}, -state => "normal");
    $::drawing->itemconfigure($self->{TD3}, -state => "normal");
}
sub hidden {
    my $self=shift;
    $::drawing->itemconfigure($self->{OD},  -state => "hidden");
    $::drawing->itemconfigure($self->{ED},  -state => "hidden");
    $::drawing->itemconfigure($self->{MD},  -state => "hidden");
    $::drawing->itemconfigure($self->{TD},  -state => "hidden");
    $::drawing->itemconfigure($self->{TD2}, -state => "hidden");
    $::drawing->itemconfigure($self->{TD3}, -state => "hidden");
}
sub redraw {
    my $self=shift;
    my $color=$self->{O}->color;
    my $color2=$self->{E}->color;
    my $xo=$self->{O}->j+$self->{O}->r*cos($self->{OA}/360*6.28);
    my $yo=$self->{O}->i+$self->{O}->r*sin($self->{OA}/360*6.28);
    my $xe=$self->{E}->j+$self->{E}->r*cos($self->{EA}/360*6.28);
    my $ye=$self->{E}->i+$self->{E}->r*sin($self->{EA}/360*6.28);
    # fixme-m best manage the representation of select item.
    my $width=
        $self->{SELECT}==0
      ? $::width_line
      : $::width_line*2;
    my $xm=$xe*$self->{SEG}+$xo*(1-$self->{SEG});
    my $ym=$ye*$self->{SEG}+$yo*(1-$self->{SEG});
    $self->cdLine("OD", $xo, $yo, $xm, $ym, $color, $width);
    if ($self->{SEG2} eq "") {
        $self->cdLine("ED", $xm, $ym, $xe, $ye, $color2, $width);
    }
    else {
        my $xp=$xe*$self->{SEG2}+$xo*(1-$self->{SEG2});
        my $yp=$ye*$self->{SEG2}+$yo*(1-$self->{SEG2});
        $self->cdLine("ED", $xp, $yp, $xe, $ye, $color2,          $width);
        $self->cdLine("MD", $xm, $ym, $xp, $yp, $self->{COULEUR}, $width);
    }
    $self->hidden;
    $self->segments($xo, $yo, $xe, $ye);
    if ($Commun::view_technique) {
        $::drawing->itemconfigure($self->{OD}, -state => "normal");
        $::drawing->itemconfigure($self->{ED}, -state => "normal");
        $::drawing->itemconfigure($self->{MD}, -state => "normal");
        # les TD sont géré avant pour le technqiue
    }
    if ($Commun::view_pique && $self->{PIQUE}) {
        $::drawing->itemconfigure($self->{OD}, -state => "normal");
        $::drawing->itemconfigure($self->{ED}, -state => "normal");
        $::drawing->itemconfigure($self->{MD}, -state => "normal");
    }
    $::drawing->itemconfigure($self->{O}->{DRAW},
        -fill => $self->select ? "grey" : "white");
    $::drawing->itemconfigure($self->{E}->{DRAW}, -fill => "white")
      ;    # fixme-m : put in Epingle.pm
}
sub inverse {
    my $self=shift;
    $self->{O}->decO();
    $self->{E}->decE();
    my $tmp=$self->{O};
    $self->{O}=$self->{E};
    $self->{E}=$tmp;
    $self->{O}->incO();
    $self->{E}->incE();
    $tmp=$self->{OA};
    $self->{OA}=$self->{EA};
    $self->{EA}=$tmp;
    $self->{SEG}=1-$self->{SEG};
    $self->{SEG2}=1-$self->{SEG2};
    $self->redraw;
}
sub selectionne {
    my $self=shift;
    $self->{SELECT}=1;
    $self->redraw();
}
sub deselectionne {
    my $self=shift;
    if ($self->{SELECT}==1) {
        $self->{SELECT}=0;
        $self->redraw();
    }
}
sub copyTranslate {
    my $self=shift;
    my ($move_i, $move_j)=@_;
    # orig+delta, cherche id de la nouvelle origine, idem extrémite,
    my $ori=Epingle::findOrCreate($self->o->i+$move_i, $self->o->j+$move_j,
        $self->o->color);
    my $extremite=
      Epingle::findOrCreate($self->e->i+$move_i, $self->e->j+$move_j,
        $self->e->color);
    # fixme-m create a duplicate fonction, with parmeter for different options
    Line->new(
        -ido         => $ori->id,
        -oa          => $self->oa,
        -ide         => $extremite->id,
        -ea          => $self->ea,
        -seg         => $self->seg,
        -seg2        => $self->seg2,
        -couleur     => $self->couleur,
        -tordre      => $self->tordre,
        -nbre_tordre => $self->nbre_tordre,
        -pique       => $self->pique
    );
}
sub print
{ # todo create a same style of print for all pm head,special,standard argument
    my $self=shift;
    my $to_string="-type Line";
    $to_string .= " -oi " . $self->{O}->i;
    $to_string .= " -oj " . $self->{O}->j;
    $to_string .= " -ei " . $self->{E}->i;
    $to_string .= " -ej " . $self->{E}->j;
    foreach my $key (
        "ID",   "OA",      "EA",     "SEG",
        "SEG2", "COULEUR", "TORDRE", "NBRE_TORDRE",
        "PIQUE"
      )
    {
        if (defined($self->{$key}) && ($self->{$key} ne "")) {
            $to_string .= " -" . lc($key) . " $self->{$key}";
        }
    }
    return "$to_string\n";
}
sub flipPique {
    my $self=shift;
    $self->{PIQUE}=$self->{PIQUE} ? 0 : 1;
    $self->redraw();
    return ($self->{PIQUE});
}
sub supprime_pique {
    my $self=shift;
    $self->{PIQUE}=0;
    $self->redraw();
}
sub supprime {
    my $self=shift;
    delete($::liste{$self->{OD}});
    delete($::liste{$self->{ED}});
    delete($::liste{$self->{MD}});
    delete($::liste{$self->{TD}});
    delete($::liste{$self->{TD2}});
    delete($::liste{$self->{TD3}});
    delete($created{$self->o->id}{$self->oa}{$self->e->id}{$self->ea});
    delete($liste{$self->id});
}
sub DESTROY {
    my $self=shift;
    $self->undoCreate;
    $self->SUPER::DESTROY();
    $self->deselectionne;
    $self->{O}->decO();
    $self->{E}->decE();
    $::drawing->delete($self->{OD});
    $::drawing->delete($self->{ED});
    $::drawing->delete($self->{MD});
    $::drawing->delete($self->{TD});
    $::drawing->delete($self->{TD2});
    $::drawing->delete($self->{TD3});
    #print "destroy off ".$self;
}
1;
