#!/usr/bin/perl -w
use strict;
use Tk;
#use diagnostics;
BEGIN{
    use FindBin qw($RealBin);
    push @INC,$RealBin;
    $::CodeDir=$RealBin;
};
use Symaxx2::LispList;
use Symaxx2::MaximaController;
use Symaxx2::ThingManager;
use Symaxx2::UIManager;
use Symaxx2::Preferences;
use Symaxx2::PopupManager;
use Text::Wrap qw(wrap $columns $huge);

if (lc($ARGV[0]) eq '-compile'){
    my $File; foreach $File('format.lisp','coeflist.lisp'){
	my $Result=`echo "compile_file(\\\"$RealBin/MaximaBatch/$File\\\");" | $::Maxima`;
	if ($Result!~/finished compiling/i){
	    print "Uh-oh...
Compilation of $File failed. 
Please make sure, that there is write access to the folder
$RealBin/MaximaBatch.

You won't be able to use the FORMAT feature. But since 
most people didn't even know that this module exists, this
should't be a major concern.

Here comes the output from Maxima: (key)\n";
	    <STDIN>;
	    print $Result;
	    exit;
	}; # if failure to compile
    }; # foreach file
    print "Finished.\nNow start Symaxx without the -compile option.\n";
    exit;
};



# A binding power of 10000 means, that it's grouped graphical, the binding is 'infinite'.
# 9900 means that I can't think of anything, that binds stronger than expr[x]
%::GraphBindPowers=('DISPLAY' => 10000,
		    'LISPLIST' => 10000,
		    'YLIST' => 10000,
		    'ROUNDBRACKETS'=> 10000,
		    'SQUAREBRACKETS'=>10000,
		    'MEXPT0' =>100,   # this to the power of sth
		    'MEXPT1'=>10000,  # sth to the power of this
		    'MEXPT'=>100,     # This is a^b

		    'FRACTION'=>10000,  # many ways to say 'a/b'
		    'MQUOTIENT'=>10000,
		    'RAT'=>10000,

		    'ROOT'=>10000,    # There is no higher hierarchy level
		    'NONE'=>10000,    # same
		    'FUNCTION'=>10000, #Any function
		    'MABS'=>10000, # Absolute (that's an operator)
		    'MLIST'=>10000,   # [...]
		    'MTIMES'=>50,     # *
		    'MQAPPLY'=>9900,     # ...[x] (a^b)[x] != a^b[x] - it binds even stronger than ^
		    'AT0'=>9800,
		    'AT1'=>10,
		    'MNCTIMES'=>50,     # . (scalar product)
		    'MPLUS'=>25,      # +
		    'MMINUS'=>25,     # -
		    'MEQUAL'=>20,     # =
		    'MLESSP'=>20,     # <
		    'MGREATERP'=>20,  # >
		    'MLEQP'=>20,      # <=
		    'MGEQP'=>20,      # >=
		    'MDEFINE'=>20,      # := (function definition)
		    'MSET'=>20,      # :: (assignment)
		    'MSETQ'=>20,       # : (assignment)
		    'SQRT'=>10000,   # 
		    'MQUOTE' => 9900,    # quotation, for example 'WATT   
		    'PROTECT' => 10000    # Protection for selecting things
		    );
# Turn this on to enable the selection functionality
# Removed from preferences
$::MaximaUseSelection=0;
&MakeUnitData;
$::MaximaUseUnits=1;
&HereComesSymaxxSlash2;
&SplashScreen;
$SIG{INT}=\(&UIManager::Quit_br); # catch Ctrl-C
# Don't remove that line! Otherwise, the watchdog will kill Symaxx, too!


{1;}; # completely useless, if not for emacs perl mode - otherwise tab doesn't work

# If a file is to be loaded via command line argument, a popup dialog may appear.
# This will only work properly, if the main window has already been drawn.
$::MainWin->waitVisibility();
# Load file given by command line argument 
if ($ARGV[0]){
    my $Filename=$ARGV[0];
    if ($Filename=~/^\//){    # Check for absolute path
	# Absolute path
	$Filename=$ARGV[0];
    } else {
	# relative path
	$Filename=`pwd`;chop $Filename;    
	$Filename.='/'.$ARGV[0];
    };
    if (-e $Filename){
	# Exists? Then load.
	$::ThingManager->Load(FILENAME=>$Filename);
    } else {
	# Does't exist? Then set at least the filename.
	$::Filename=$Filename;
	# Append .mth to the global filename.
	if ($::Filename !~/\.mth$/){$::Filename.='.mth';};

    };  
    $::UIManager->SetTitle;
    
};
MainLoop;
exit;

# Avoid error message 'Variable only used once'
use vars qw(%GraphBindPowers $WorkDir);
sub HereComesSymaxxSlash2{
    $::MaximaLog='Maxima has not yet been invoked.';
    # Maybe this has to be changed, if the documentation is in another directory.    
    
    # The working dir is session-specific. Creating a new file does not need a new dir
    if (!defined ($::TempDir)){
	$::TempDir='/tmp/symaxx2tmp'.int(rand(10000000)).time;
	system ("mkdir $::TempDir");
	$::TempDirDeleteAutomaticallyAtFinish=1;
    } else {
	if (!-e $::TempDir){system("mkdir $::TempDir");};
    };
    if (!-e $::TempDir){
	die "***ERROR***\nUnable to create temporary working directory $::TempDir";
    };

    $::WorkDir=`pwd`;chop $::WorkDir;
#    print "Idee: Select everything above/below/left/right of mouse (like insert cell in spreadsheet)\n";
#    print "Idee: Blindref-flag (alle Referenzen zu diesem Ausdruck werden nicht gezeichnet)\n"; 
#    print "Todo: prevent, that the same file is opened from several Symaxxes at the same time (locking)\n";
#    print "Todo: Use dispform()\n";
    $::ThingManager=ThingManager::New;
    $::PopupManager=PopupManager::New;
    @::Filetypes=(['Symaxx/2','.mth'],['Hope you know what you are doing...','*']);
    $::Revision='0.16';
    $::Filename='untitled.mth';
    $::DefaultFilename=$::Filename;
    $::MainWin=undef;
    $::UIManager=UIManager::New();
    $::UIManager->SetTitle;
    $::WrapDefaultColumns=50;
    $::ThingManager->Redraw('ALL'=>1);
    $::MainDirty=0;
};


sub SplashScreen{
    my @TipOfTheDay=("Control-Space evaluates (if the cursor is not editing text)","When editing, Shift-Return enters and evaluates.","How about printing the manual?","The Maxima manual is the ultimate source of information for all questions not directly related to Symaxx.","When you have found a bug, please report it (see About dialog for contact info)","You can copy and paste text selections with Control-C and Control-V","For results or 'important' notes, you can use the RED(x),GREEN(x),BLUE(x),GRAY(x)-functions to highlight.","Instead of using the scrollbars, you can drag the background with the left mouse key.","If you don't understand, what's going on, check the log (Ctrl-i)","When you are editing the `doc`-line, you can insert a line break with Ctrl-return.","The 'describe'-function does a full-text search through the whole maxima manual. It is not yet supported in Symaxx. But of course you can start another maxima session from the console and type 'describe(keyword)' there! (quit with CTRL-D).","You can define a function with := as in f(x):=sin(x). The argument x gets evaluated BEFORE the function. You can also define a macro with ::= as in g(x)::=cos(x). The arguments x gets substituted into the function (without prior evaluation).","When editing a command, you can enter\n-REF[] by pressing ALT-r,\n-%pi by pressing ALT-p,\n-%i by pressing ALT-i.","Maxima will only accept numbers in exponential notation if you use a decimal point (for example 1.e4 is 10000, 1e4 is an error).","Predefined constants in Maxima are:\n%pi=3.14...\n%i=sqrt(-1)\n%e=2.718...","If you can't succeed to evaluate an exponential function numerically, make a definition DEMOIVRE:TRUE",'You can customize a lot of options, if you edit /Symaxx2/Preferences.pm with a text editor (recommended only for advanced users).',
'If you add a $ to the end of your input, Symaxx will not show the Maxima output. Adding a ; will turn it on again.');
    my $SplashText="Welcome to Symaxx/2 $::Revision!\nPress the middle mouse button to create an object, place and move with the left button. The right button shows the properties dialog. Press the EVAL button to run Maxima.\nWhen you have placed an object, the upper line is the command, the lower line the result. Usually you edit only the command.\nView the manual with F1 or look for the file Manual.pdf in the Symaxx2/Doc folder.";
    $SplashText.="\n******Tip of the day******\n";
    $SplashText.=@TipOfTheDay[rand($#TipOfTheDay+1)];
    $Text::Wrap::columns=$::WrapDefaultColumns;
    $SplashText=wrap('','',$SplashText);
    my @Textlist=split(/\n/,$SplashText);
    my $y=40; my $y1=$y;
    my $Line;while ($Line=shift @Textlist){
	$::GlobalCanvas->createText(60,$y+=15,-text =>$Line,-anchor =>'w',
				    -tags=>'PRECISESELECTIONCURSOR');    
    };
    my $i; for ($i=0;$i<=5;$i++){
	$::GlobalCanvas->createRectangle(10+5*$i,$y1-30+5*$i,
					 400+5*$i,$y+20+5*$i,				 
					 -tags =>'PRECISESELECTIONCURSOR', # gets deleted at first mouse click
					 -outline => 'orange');
    };
    $::UIManager->RecalcCanvas;
};
sub MakeUnitData{
    my $UnitData='NEWTON: NEWTONS=>N
JOULE: JOULES=>J
WATT: WATTS=>W
ACRE: ACRES
AMPERE: AMPERES: AMP: AMPS=>A
OHM: OHMS=>Ohm
ANGSTROM: ANGSTROMS
ARE: ARES
ASTRONOMICALUNIT=>AU
ATMOSPHERE: ATMOSPHERES
BAR: BARS
BARRELDRY: BARRELSDRY
BARREL: BARRELS: BARRELSLIQUID
BARRELOIL: BARRELSOIL
BARYL: BARYLS
BOLT: BOLTS
BTU: BTUS:BRITISHTHERMALUNIT: BRITISHTHERMALUNITS
BUSHEL: BUSHELS
CANDLE: CANDLES
CENTIGRAM: CENTIGRAMS
CENTILITER: CENTILETERS
CENTIMETER: CENTIMETERS=>cm
CENTIMETEROFMERCURY: CENTIMETERSOFMERCURY
CHAIN: CHAINS
CIRCULARMIL: CIRCULARMILS
CORD: CORDS
COULOMB: COULOMBS=>C
CUP: CUPS
CYCLE: CYCLES
DALTON: DALTONS
DAY: DAYS
DECIGRAM: DECIGRAMS
DECILITER: DECILITERS
DECIMETER: DECIMETERS
DEGREE: DEGREES: DEG=>deg
DEGREEF: DEGF: DEGREEFAHRENHEIT
DEGREEC: DEGC: DEGREECENTIGRADE: DEGREECELSIUS
DEGREER: DEGR: DEGREERANKINE
DEKAGRAM: DEKAGRAMS
DEKALITER: DEKALITERS
DEKAMETER: DEKAMETERS
DYNE: DYNES
ELL: ELLS
EMPICA: EMSPICA
ERG: ERGS
FARADS: FARAD=>F
FARADAY: FARADAYS
FATHOM: FATHOMS
FEET: FOOT: FT=>ft
FEETOFWATER: FOOTOFWATER
FLUIDOUNCE: FLUIDOUNCES
FOOTCANDLE: FOOTCANDLES
FURLONG: FURLONGS
GALLON: GALLONS
GALLONIMPERIAL
GILL: GILLS
GRADE: GRADES
GRAM: GRAMS: GM=>g
GRAMCALORIE: GRAMCALORIES
HAND: HANDS
HECTOGRAMS: HECTOGRAM
HECTOLITER: HECTOLITERS
HECTOMETER: HECTOMETERS
HECTOWATT: HECTOWATTS
HENRIES: HENRY=>H
HOGSHEAD: HOGSHEADS
HORSEPOWER: HP=>hp
HOUR: HOURS=>h
INCH: INCHES: IN=>in
INCHOFMERCURY: INCHESOFMERCURY
JOULES: JOULE
KILOGRAMS: KG: KILOGRAM=>kg
KILOMETER: KILOMETERS: KM=>km
KILOWATTS: KILOWATT=>kW
KNOT: KNOTS
LEAGUE: LEAGUES
LIGHTYEAR: LIGHTYEAR
LINK: LINKS
LINKSURVEYOR
LITER
LUMEN
LUX
MEGOHM: MEGOHMS
METERS: M: METER=>m
MICROFARAD: MICROFARADS
MICROGRAM: MICROGRAMS
MICROHM:MICROHMS
MICROLITER: MICROLITERS
MICRON: MICRONS
MICROSECOND: MICROSECONDS
MILENAUTICAL: MILESNAUTICAL
MILE: MILES
MILLIER: MILLIERS
MILLIMICRON: MILLIMICRONS
MILLIGRAM: MILLIGRAMS
MILLIHENRY: MILLIHENRIES
MILLILITER: MILLILITERS
MILLIMETER: MILLIMETERS=>mm
MILLISECOND: MILLISECONDS=>ms
MIL: MILS
MINUTE: MINUTES: MIN=>min
MINERSINCH: MINERSINCHES
MINIMS
MYRIAGRAM: MYRIAGRAMS
MYRIAMETER: MYRIAMETERS
MYRIAWATT: MYRIAWATTS
NEPER: NEPERS
NEWTONS: NEWTON=>N
OHMS: OHM
PARSEC: PARSECS
PECK: PECKS
PINT: PINTS
POUNDAL: POUNDALS
POISE
POUND: POUNDS: LB: LBF
POUNDMASS: POUNDSMASS: LBM
OUNCE: OUNCES: OUNCEAVOIRDUPOIS
OUNCETROY: OUNCESTROY
QUARTDRY: QUARTSDRY
QUART: QUARTS: QT
RADIANS: RAD=>rad
REVOLUTION: REVOLUTIONS
ROD: RODS
SLUG: SLUGS
SECOND: SECONDS: SEC=>s
SPHERE: SPHERES
STOKE: STOKES
STATCOULOMB
STERADIANS
TABLESPOON: TABLESPOONS
TEASPOON
VOLTS: VOLT=>V
WATTS: WATT=>W
WEEK: WEEKS
YARD: YARDS
';
    %::Units=();
    my @UnitData2=split(/\n/,$UnitData);
    my $UnitData3;foreach $UnitData3(@UnitData2){
	# look out for ... => bla  
	my $Abbrev='';
	if ($UnitData3=~/^(.*)\s*\=\>\s*(.*)\s*$/){
	    $UnitData3=$1;
	    $Abbrev=$2;
	};
	my @UnitData4=split(/\:/,$UnitData3);
	my $UnitData5; foreach $UnitData5(@UnitData4){
	    $UnitData5=~s/^(\s*)//g; # leading space
	    $UnitData5=~s/(\s*)$//g; # trailing space
	    $::Units{$UnitData5}=$Abbrev;
	};
	if ($UnitData3=~/^\s*(\S+)\:/){
	    push @::AllUnits,$1;
	};
    };
    @::AllUnits=sort @::AllUnits;
};
