#!/usr/bin/perl
#  pdnmesh - a 2D finite element solver
#    Copyright (c) 2001 Sarod Yatawatta <sarod@cs.pdn.ac.lk>  
#  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
#
#>>>>>> d2m - converts .dxf files to ones for pdnmesh input <<<<<<
#




$npoints = 0; # point numbers
$lcount = 0; # line count 
$layercount =0; # layers


# a list of colours
$RESET = 0;
$BRIGHT = 1;
$WHITE = 7;
$BLACK = 0;
$RED = 1;
$GREEN = 2;
$YELLOW = 3;
$BLUE = 4;
$MAGENTA = 5;
$CYAN = 6;

#a subroutine for changing colors
sub change_color {
        # get parameters
	($attr,$fg,$bg) = @_;
	printf "%c[%d;%d;%dm", 0x1B, $attr, $fg+30, $bg+40;
}

#subroutine for printing info
sub usage {
    printf "usage: d2m input.dxf output_file \n";
    printf "output_file can be used in pdnmesh\n";
    
}


#####################################################################################
#####################################################################################

if ( scalar(@ARGV) == 0 ) {
     &usage;
	  exit(1);
}

if ( -r @ARGV[0] ) {
 #open input file
open(IN,"< @ARGV[0]") || die "can't open input file @ARGV[0]\n";
} else  {
    print "can't open input file @ARGV[0]\n";
    &usage;
    exit(1);
}

#open output file
open(OUTFILE,"> @ARGV[1]") || die "can't open output file @ARGV[2]\n";

##
## uncomment the following line for debug output
# open debug file
#  open(ERRFILE,"> $debug")  ||  die "can't open debug file \n";


print ERRFILE "in @ARGV[0] out @ARGV[1]\n";

# read input
while (defined($sline = <IN>)) {
    
    if ( $sline =~ /LINE/ ) {
	chomp; # remove newline
	print ERRFILE "line found \n";
	# now read layer
	while ( defined($sline = <IN>) ) {
	    if ( $sline =~ /^[a-zA-Z]+/ ) { #layer name only alphabetic
		chop $sline;
		$layer_name = $sline;
		
		print ERRFILE "layer $layer_name found\n";
		last;
	    }
	}
	# now read until start x coord appears
	while ( defined($sline = <IN>) ) {
	    if ( $sline =~ /10/ ) {
		print ERRFILE "x found\n";
		last;
	}
	}
	chomp;
	chomp ($sline = <IN>);
	print ERRFILE "$sline \n";
	$xval = $sline;
	#now read until start y coord appears
	while ( defined($sline = <IN>) ) {
	    if ( $sline =~ /20/ ) {
		print ERRFILE "y found\n";
		last;
	    }
	}
	chomp;
	chomp ($sline = <IN>);
	print ERRFILE "$sline \n";
	$yval = $sline;
	
	# now that we have read x and y build up point data
	$point = {
	    x => $xval,
	    y => $yval,
	};
	
	# check hash for existance of point
	if ( exists($pt_num{"$xval$yval"}) ) {
	    print ERRFILE "point exists\n";
	    $i = $pt_num{"$xval$yval"}; 
	} else {
	    
	    print ERRFILE "point hash ";
	    print ERRFILE "$xval$yval\n";
	    $pt_num{"$xval$yval"} = $npoints;
	    
	    #insert point at $npoints location
	    $points[$npoints] = $point;
	    
	    #store point number for line
	    $i = $npoints;
	    #increment point count
	    $npoints++;
	    
	}
	
	# now read until end x coord appears
	while ( defined($sline = <IN>) ) {
	    if ( $sline =~ /11/ ) {
		print ERRFILE "x found\n";
		last;
	    }
	}
	chomp;
	chomp ($sline = <IN>);
	print ERRFILE "$sline \n";
	$xval = $sline;
	#now read until end y coord appears
	while ( defined($sline = <IN>) ) {
	    if ( $sline =~ /21/ ) {
		print ERRFILE "y found\n";
		last;
	    }
	}
	chomp;
	chomp ($sline = <IN>);
	print ERRFILE "$sline \n";
	$yval = $sline;
	
	# now that we have read x and y build up point data
	$point = {
	    x => $xval,
	    y => $yval,
	};
	
	# check hash for existance of point
	if ( exists($pt_num{"$xval$yval"}) ) {
	    print ERRFILE "point exists\n";
	    $j = $pt_num{"$xval$yval"}; 
	} else {
	    $pt_num{"$xval$yval"} = $npoints;
	    
	    print ERRFILE "point hash ";
	    print ERRFILE "$xval$yval\n";
	    #insert point at $npoints location
	    $points[$npoints] = $point;
	    
	    #store point number for line
	    $j = $npoints;
	    #increment point count
	    $npoints++;
	    
	}
	
	# now insert line into line database 
	if (  exists($line_data{"$i$j"}) || exists($line_data{"$j$i"}) ) {
	    print ERRFILE "line found earlier\n";
	    
	    # should check for line $j $i as well
	    if ( exists($line_data{"$i$j"}) ) {
		$lnumber = $line_data{"$i$j"};
	    } else {
		$lnumber = $line_data{"$j$i"};
	    }
	} else {
	    print ERRFILE "new line $i $j\n";
	    # new line
	    if ( $i < $j ) {
		$line = {
		    p1 => $i,
		    p2 => $j,
		};
		
		#build new hash 
		$line_data{"$i$j"} = $lcount; 
	    } else {
		$line = {
		    p1 => $j,
		    p2 => $i,
		};
		
		#build new hash 
		$line_data{"$j$i"} = $lcount; 
	    } 
	    
	    #insert into array
	    @lines[$lcount] = $line;
	    
	    #remember new line number
	    $lnumber = $lcount;
	    
	    $lcount = $lcount +1;
	}
	
	
	# now update layers 
	# include layer only if is is not "none" 
	if ($layer_name ne "none")  {
	    if ( exists($layer_data{"$layer_name"}) ) {
		push @{$layer_data{"$layer_name"}->{lns}}, "$lnumber";
		printf ERRFILE "layer %s has %d lines\n", $layer_name, 
		scalar @{$layer_data{"$layer_name"}->{lns}}-1;
	    } else {
                # new layer
		$layer = {
		    name => "$layer_name",
		    lns => ["$lnumber"], #empty
		};
		
		# create hash
		$layer_data{"$layer_name"} = $layer;
		$layercount++;
		
	    }
	}
    }
}

# print summery
print ERRFILE "found $npoints points\n";
print ERRFILE "found $lcount lines\n";

# points
for ( $i = 0; $i < $npoints; $i++ ) {
    $tempp = $points[$i];
    print ERRFILE "no = $i x = $tempp->{x} y = $tempp->{y}\n";
}

#lines
for ( $i = 0; $i < $lcount; $i++ ) {
    $templ = @lines[$i];
    print ERRFILE "no = $i p1 = $templ->{p1} p2= $templ->{p2}\n";
}

#layers
foreach $key ( keys (%layer_data)) {
    
    $j = scalar @{$layer_data{"$key"}->{lns}};
    print ERRFILE "layer $key has $j lines\n";
    for ( $i =0; $i < $j; $i++ ) {
	printf ERRFILE "%s\n", @{$layer_data{"$key"}->{lns}}[$i] ;
    }
}


#arrange the lines of each boundary in ccw order

foreach $key ( keys (%layer_data)) {
#first get a line
    $l1 = pop(  @{$layer_data{"$key"}->{lns}} );
# store it in temp array
#first make array empty
    @tempa = [];
    push(@tempa, $l1);
    
#get the two points of that line
    $p1 = @lines[$l1]->{p1};
    $p2 = @lines[$l1]->{p2};
    print ERRFILE "points $p1 $p2 in $l1\n";
    $p3 = $p2;
# now find RESETother line with point p2
    while ( $j > 0 ) {
	$found =0;
	$i =0;
	$j = scalar @{$layer_data{"$key"}->{lns}};
	print ERRFILE "array length $j\n";
	while ( ( $i < $j)  && ( $found == 0 )) {
	    $l1 = @{$layer_data{"$key"}->{lns}}[$i];
	    printf ERRFILE "examining %s for %s\n", $l1, $p3;  
	    $p1 = @lines[$l1]->{p1};
	    $p2 = @lines[$l1]->{p2};
	    if ( $p1 == $p3 ) {
		# found!
		# remove line from boundary
		splice(  @{$layer_data{"$key"}->{lns}}, $i, 1 );
		#add it to temp array
		push(@tempa, $l1);
		$p3 = $p2;
		print ERRFILE "found $i as next $p3\n";
		$found = 1;
		last; #end search 
	    } elsif ( $p2 == $p3 ) {
		# found!
		# remove line from boundary
		splice(  @{$layer_data{"$key"}->{lns}}, $i, 1 );
		#add it to temp array
		push(@tempa, $l1);
		$p3 = $p1;
		print ERRFILE "found $i as next $p3\n";
		$found = 1;


		last; #end search 
	    } 
	    
	    print ERRFILE "found? $found\n";
	    $i++;
	}
	
	if ( $found == 0 ) {
	    # no line found 
      printf ERRFILE "boundary $key not closed\n";
		last;
  }
	
	
    }
    print ERRFILE "@tempa\n";
#now copy @tempa to original
#now copy
    $j = scalar @tempa;
    for ( $i=1; $i < $j; $i++ ) {
	$l1 = pop(@tempa);
	push(  @{$layer_data{"$key"}->{lns}}, $l1);
    }
    
}


if ( -w ERRFILE ) {
close(ERRFILE) || die "can't close error file $!";
}

close(IN) || die "can't close input $!";



############################################################################################
############################################################################################

#now print output for pdnmesh


print OUTFILE "#\tAutomatically generated by d2m from @ARGV[0],\n";
print OUTFILE "#\tthis file can be used as input for pdnmesh.\n";
print OUTFILE "#\tBefore that PLEASE fill in any missing detail of this file.\n";
print OUTFILE "#\tEmpty and lines starting with a '#' are ignored.\n";
print OUTFILE "###########################################################################\n";
print OUTFILE "###########################################################################\n";
print OUTFILE "\n\n";

print OUTFILE "#\tno. of points\n";
print OUTFILE "$npoints \n";

&change_color($BRIGHT,$YELLOW,$BLACK);
print "found $npoints points \n";
print "please enter <potential> <fixed=1,var=0> for them\n";
&change_color($RESET,$YELLOW,$BLACK);

print OUTFILE "\n";
print OUTFILE "#\tpoint data [5 entities in each row]\n";
print OUTFILE "#\t| point_no | x coord | y coord | potential | fixed=1/variable=0 |\n";
# points
for ( $i = 0; $i < $npoints; $i++ ) {
    $tempp = $points[$i];

    &change_color($BRIGHT,$GREEN,$BLACK);
    print "$i $tempp->{x} $tempp->{y} ";
    &change_color($RESET,$GREEN,$BLACK);

    chomp ( $sline = <STDIN> );
	 ($rho, $eps) = $sline ;
    print OUTFILE "$i $tempp->{x} $tempp->{y} $rho $eps\n";
}

&change_color($BRIGHT,$YELLOW,$BLACK);
print "found $lcount lines\n";
print "please enter <fixed=1,var=0> for them (or Dirichlet, Neumann)\n";
&change_color($RESET,$YELLOW,$BLACK);

print OUTFILE "\n\n";
print OUTFILE "#\tno. of edges\n";
print OUTFILE "$lcount \n";

print OUTFILE "\n";
print OUTFILE "#\tline data [4 entities in each row]\n";
print OUTFILE "#\t| line_no | point 1 | point 2 |  fixed=1/variable=0 |\n";
#lines
for ( $i = 0; $i < $lcount; $i++ ) {
    $templ = @lines[$i];

    &change_color($BRIGHT,$GREEN,$BLACK);
    print "$i $templ->{p1} $templ->{p2} ";
    &change_color($RESET,$GREEN,$BLACK);

    chomp ( $sline = <STDIN> );
	 $rho = $sline ;
    print OUTFILE "$i $templ->{p1} $templ->{p2} $rho\n";
}

print OUTFILE "\n\n";
print OUTFILE "#\tno. of boundaries\n";
print OUTFILE "$layercount \n";



&change_color($BRIGHT,$YELLOW,$BLACK);
print "found $layercount boundaries\n";
&change_color($RESET,$YELLOW,$BLACK);

#layers
#first "default" layer
$j = scalar @{$layer_data{"default"}->{lns}};
#no.of lines colsed? rho epsilon


&change_color($BRIGHT,$YELLOW,$BLACK);
print "first the outer boundary with $j edges\n";
print "enter <f=1,n=0> <epsilon> <rho> for this boundary\n";
&change_color($RESET,$YELLOW,$BLACK);

#$done = 0; # false

#while ( $done == 0 ) {

&change_color($BRIGHT,$GREEN,$BLACK);
print "$j ";
&change_color($RESET,$GREEN,$BLACK);

    chomp ( $sline = <STDIN> );
	 ($i, $eps, $rho) = split(/\s+/,$sline) ;

#     print "i $i eps $eps rho $rho";
#	 if ( $eps>= 0 && $rho >= 0 ) {
#	   $done = 1;
#	 }
#} 

print OUTFILE "\n";
print OUTFILE "#\tfirst the outer boundary('default' layer) [4 entities in each row]\n";
print OUTFILE "#\t| edges | triangles will be kept? | epsilon | rho |\n";
print OUTFILE "$j $i $eps $rho\n";

print OUTFILE "\n";
print OUTFILE "#\tnow the line numbers in outer ('default')  boundary\n";


&change_color($BRIGHT,$YELLOW,$BLACK);
print "the line numbers in boundary 'default'\n";
&change_color($RESET,$YELLOW,$BLACK);

for ( $i =0; $i < $j; $i++ ) {
    printf "%s\n", @{$layer_data{"default"}->{lns}}[$i] ;
    printf OUTFILE "%s\n", @{$layer_data{"default"}->{lns}}[$i] ;
}

print OUTFILE "\n\n";
print OUTFILE "#\tnow other boundaries\n";

&change_color($BRIGHT,$YELLOW,$BLACK);
print "other boundaries\n";
&change_color($RESET,$YELLOW,$BLACK);

#now other layers
foreach $key ( keys (%layer_data)) {
    if ( $key ne "default" ) {
	$j = scalar @{$layer_data{"$key"}->{lns}};
	#no.of lines closed? rho epsilon
    &change_color($BRIGHT,$YELLOW,$BLACK);	
    print "enter <f=1,n=0> <epsilon> <rho> for boundary '$key'\n";
    &change_color($RESET,$YELLOW,$BLACK);

    &change_color($BRIGHT,$GREEN,$BLACK);
    print "$j ";
    &change_color($RESET,$GREEN,$BLACK);

    chomp ( $sline = <STDIN> );

	 ($i, $eps, $rho) = split(/\s+/,$sline) ;
	
    print OUTFILE "\n";	
    printf OUTFILE "#\tboundary ('%s' layer) [4 entities in each row]\n", $key;
    print OUTFILE "#\t| edges | triangles will be kept? | epsilon | rho |\n";
    print OUTFILE "$j $i $eps $rho\n";	

   print OUTFILE "\n";
   print OUTFILE "#\tthe line numbers in boundary '$key'\n";


   &change_color($BRIGHT,$YELLOW,$BLACK);
   print "the line numbers in boundary '$key'\n";
   &change_color($RESET,$YELLOW,$BLACK);

	#should print in ccw order
	for ( $i =0; $i < $j; $i++ ) {
	    printf "%s\n", @{$layer_data{"$key"}->{lns}}[$i] ;
            printf OUTFILE "%s\n", @{$layer_data{"$key"}->{lns}}[$i] ;
	}
    }
}


#reset back to default colour
&change_color($RESET,$WHITE,$BLACK);


print "the output has been written to '@ARGV[1]'\n";
print "please check this file and run pdnmesh\n";
print "\ngood luck!\n";

close(OUTFILE) || die "can't close outfile $!";
