/*   
 *   Copyright 2006 Owen Piette
 *   See license.txt for terms.
 *
 */


#include <stdio.h>
#include <iostream>
#include <string.h>

#include "Sand-4.h"
#include <wx/wx.h>
#include <wx/dcscreen.h>
#include <wx/dcbuffer.h>
#include <wx/datetime.h>
#include <wx/file.h>
#include <wx/image.h>
#include <wx/thread.h>
#include <wx/event.h>
#include <wx/menuitem.h>
#include <wx/treectrl.h>
#include <wx/tglbtn.h>
#include <wx/thread.h>

#include "refresh.xpm"
#include "pause.xpm"

#define TIMERINTERVAL 33

#define MAXNUMBEROFELEMENTS 128
#define MAXSIZE 1280*1024

#define drawData(center){\
  bitmapdata[((center)*3)+0] = colors[data[center]][energy[center]].Red();\
  bitmapdata[((center)*3)+1] = colors[data[center]][energy[center]].Green();\
  bitmapdata[((center)*3)+2] = colors[data[center]][energy[center]].Blue();\
};


#define found(center, other, cx, cy, ox, oy){\
  unsigned char t = data[center];\
  data[center] = data[other];\
  data[other] = t;\
  t = energy[center];\
  energy[center] = energy[other];\
  energy[other] = t;\
  drawData(center);\
  drawData(other);\
  calc[center] = true;\
  if (data[other] != 0)\
    calc[other] = true;\
};


#define checkForTransformation(center, other, cx, cy, ox, oy){\
  unsigned char t1 = data[center];\
  unsigned char t2 = data[other];\
  \
  if (data[other] != 0){\
    if (energy[other] > energy[center]){\
      int de = energy[other]-energy[center];\
      de = (int)ceil(conductivity[data[center]]*double(de));\
\
      energy[other] -= de;\
      energy[center] += de;\
\
      if (energy[center] > 99)\
	energy[center] = 99;\
\
      drawData(center);\
      drawData(other);\
    }\
  }\
  \
  if (trans_prob[t1][t2][energy[t1]] == 0) break;\
  if (doWalls && (ox == 0 || ox == g_width-1 || oy == 0 || oy == g_height-1))\
    break;\
  if (rand() < ctrans_prob[t1][t2][energy[t1]]){\
    int r = (int)round(99.0*(double(rand())/double(RAND_MAX)));\
    data[center] = trans_center[t1][t2][r];\
    data[other] = trans_neighbor[t1][t2][r];\
    energy[center] = 0;\
    energy[other] = 0;\
    drawData(center);\
    drawData(other);\
    calc[center] = true;\
    calc[other] = true;\
    break;\
  }\
  break;\
};

BEGIN_EVENT_TABLE(Canvas, wxWindow)
  EVT_PAINT(Canvas::OnPaint)
  EVT_ERASE_BACKGROUND(Canvas::OnEraseBG)
  EVT_RIGHT_DOWN(Canvas::OnMouseRightDown)
  EVT_LEFT_DOWN(Canvas::OnMouseLeftDown)
  EVT_LEFT_UP(Canvas::OnMouseLeftUp)
  EVT_MOTION(Canvas::OnMouseMove)
  EVT_TIMER(999, Canvas::OnTimer)
  EVT_TIMER(998, Canvas::OnSecondTimer)
END_EVENT_TABLE()


BEGIN_EVENT_TABLE(MainFrame, wxFrame)
  EVT_SET_FOCUS(MainFrame::OnMove)
  EVT_SIZE(MainFrame::OnSize)
  EVT_TREE_SEL_CHANGED(1000, MainFrame::OnElementChoice)
  EVT_LISTBOX(1001, MainFrame::OnChoice)

  EVT_BUTTON(1025, MainFrame::OnButton)
  EVT_BUTTON(1026, MainFrame::OnToggleButton)

  EVT_MENU(1002, MainFrame::OnMenu)
  EVT_MENU(1003, MainFrame::OnMenu)
  EVT_MENU(1004, MainFrame::OnMenu)
  EVT_MENU(1005, MainFrame::OnMenu)
  EVT_MENU(1006, MainFrame::OnMenu)
  EVT_MENU(1007, MainFrame::OnMenu)

  EVT_MENU(1050, MainFrame::OnMenu)
  EVT_MENU(1051, MainFrame::OnMenu)
  EVT_MENU(1052, MainFrame::OnMenu)
  EVT_MENU(1053, MainFrame::OnMenu)
  EVT_MENU(1054, MainFrame::OnMenu)
  EVT_MENU(1055, MainFrame::OnMenu)
  EVT_MENU(1056, MainFrame::OnMenu)
END_EVENT_TABLE()

IMPLEMENT_APP(Sand)


char defaultFileContents[] = "#wxSand: Owen Piette's Falling Sand Game\n\
#Version 4, File subversion 2\n\
#element element r g b gravity slip density conductivity visible\n\
group   Waters  Water  Steam  Saltwater  Spout\n\
sources Sand    Water  Salt   Oil\n\
\n\
element	Empty	0	0	0	0.000000	1.000000	0.000000	0.000000	1\n\
element	Wall	128	128	128	0.000000	0.000000	1.000000	0.500000	1\n\
element	Fire	247	63	63	-1.000000	1.000000	0.000000	1.100000	1\n\
self	0.050000	Fire	1.0000	Empty	\n\
neighbor 0.9	Fire	Water	1.0	Empty		Steam\n\
neighbor 0.75	Fire	Oil	1.0	Fire		Fire\n\
neighbor 1.0	Fire	Plant	1.0	Fire		Fire\n\
neighbor 0.005	Fire	Cera	1.0	MoltenCera	Ember\n\
element	Water	32	32	255	0.700000	1.000000	0.500000	0.000000	1\n\
element	Plant	32	204	32	0.000000	0.000000	1.000000	0.000000	1\n\
neighbor 0.2	Plant	Water	1.0	Plant	Plant\n\
element	Sand	238	204	128	0.900000	0.500000	0.900000	0.000000	1\n\
element	Spout	10	100	10	0.000000	0.000000	1.000000	0.000000	1\n\
neighbor 0.75	Spout	Empty	1.0	Spout		Water\n\
neighbor 0.5	Spout	Sand	1.0	Empty		Empty\n\
element	Cera	238	221	204	0.000000	0.000000	1.000000	0.000000	1\n\
element	???	231	7	231	0.000000	1.000000	1.000000	0.000000	1\n\
self	0.100000	???	1.0000	Leftover???\n\
neighbor 1.0	???	Empty	1.0	???	???\n\
neighbor 1.0	???	Wall	1.0	???	???\n\
neighbor 1.0	???	Fire	1.0	???	???\n\
neighbor 1.0	???	Water	1.0	???	???\n\
neighbor 1.0	???	Sand	1.0	???	???\n\
neighbor 1.0	???	Spout	1.0	???	???\n\
neighbor 1.0	???	Cera	1.0	???	???\n\
neighbor 1.0	???	Oil	1.0	???	???\n\
neighbor 1.0	???	Salt	1.0	???	???\n\
neighbor 1.0	???	Ember	1.0	???	???\n\
neighbor 1.0	???	MoltenCera	1.0	???	???\n\
neighbor 1.0	???	Steam	1.0	???	???\n\
neighbor 1.0	???	Saltwater	1.0	???	???\n\
neighbor 1.0	???	Torch	1.0	???	???\n\
neighbor 0.2	???	Leftover???	1.0	Leftover???	Leftover???\n\
element	Oil	128	64	64	0.700000	1.000000	0.200000	0.000000	1\n\
element	Salt	255	255	255	0.900000	0.400000	0.900000	0.000000	1\n\
element	Ember	200	50	50	0.000000	0.200000	1.000000	0.000000	1\n\
self	0.002000	Ember	1.0000	Fire\n\
neighbor 0.2		Ember	Empty	1.0	Ember	Fire\n\
neighbor 0.9		Ember	Water	1.0	Empty	Steam\n\
neighbor 0.75		Ember	Oil	1.0	Ember	Fire\n\
neighbor 1.0		Ember	Plant	1.0	Ember	Fire\n\
neighbor 0.005		Ember	Cera	1.0	MoltenCera	Ember\n\
element	MoltenCera	255	220	200	0.800000	1.000000	1.000000	0.000000	0\n\
neighbor 0.01	MoltenCera	Wall	1.0	Cera	Wall\n\
neighbor 0.01	MoltenCera	Water	1.0	Cera	Water\n\
neighbor 0.01	MoltenCera	Sand	1.0	Cera	Sand\n\
neighbor 0.01	MoltenCera	Spout	1.0	Cera	Spout\n\
neighbor 0.01	MoltenCera	Cera	1.0	Cera	Cera\n\
neighbor 0.01	MoltenCera	Oil	1.0	Cera	Oil\n\
neighbor 0.01	MoltenCera	Salt	1.0	Cera	Salt\n\
neighbor 0.01	MoltenCera	Saltwater	1.0	Cera	Saltwater\n\
element	Steam	85	85	255	-1.000000	1.000000	0.010000	0.000000	1\n\
self	0.001000	Steam	1.0000	Water\n\
element	Saltwater	0	0	150	0.700000	0.000000	0.500000	0.000000	1\n\
neighbor 0.004	Water	Salt	1.0	Saltwater		Saltwater\n\
neighbor 0.00001	Saltwater	Saltwater	1.0	Salt		Water\n\
neighbor 0.04		Saltwater	Water		1.0	Water		Saltwater\n\
neighbor 0.9		Saltwater	Fire		1.0	Salt		Steam\n\
element	Torch	100	0	0	0.000000	1.000000	1.000000	1.000000	1\n\
neighbor 0.2	Torch	Empty	1.0	Torch		Fire\n\
neighbor 0.2	Torch	Water	1.0	Torch		Steam\n\
neighbor 0.2	Torch	Saltwater	0.5	Torch		Steam	0.5	Torch	Salt\n\
neighbor 0.2	Torch	Oil	1.0	Torch		Fire\n\
neighbor 0.2	Torch	Plant	1.0	Torch		Fire\n\
neighbor 0.2	Torch	Cera	1.0	Torch		MoltenCera\n\
element	Leftover???	200	0	0	0.000000	0.000000	1.000000	0.000000	0\n\
self	0.005000	Leftover???	1.0000	Empty	\n\
\n\
";

//element Flies   200     100     100     0   1  0  0  1
//neighbor 0.2	Flies	Empty	1.0	Empty		Flies


//Things that change with conductivity: color, energy, trans_prob, death_prob (ctrans_prob, cdeath_prob)


wxString names[MAXNUMBEROFELEMENTS];
wxColor colors[MAXNUMBEROFELEMENTS][100];

double gravity[MAXNUMBEROFELEMENTS];
double slip[MAXNUMBEROFELEMENTS];
double density[MAXNUMBEROFELEMENTS];
double conductivity[MAXNUMBEROFELEMENTS];
bool visible[MAXNUMBEROFELEMENTS];

double death_prob[MAXNUMBEROFELEMENTS][100];
char death_center[MAXNUMBEROFELEMENTS][100];

double trans_prob[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS][100];   //Probability that something will happen.
unsigned char trans_center[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS][100];//Probability that that something will be this.
unsigned char trans_neighbor[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS][100];

int cgravity[MAXNUMBEROFELEMENTS];
int ccodensity[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS];
int ccoslip[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS];
int ccogravityslip[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS];
int ccodensityslip[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS];
int ccogravitydensity[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS];

int ctrans_prob[MAXNUMBEROFELEMENTS][MAXNUMBEROFELEMENTS][100];
int cdeath_prob[MAXNUMBEROFELEMENTS][100];

wxString groupNames[MAXNUMBEROFELEMENTS];
int groups[MAXNUMBEROFELEMENTS];
int numberOfGroups;

int numberOfElements;

char sources[MAXNUMBEROFELEMENTS];
int numberOfSources;


MainFrame* g_mainFrame;
Canvas* g_canvas;
unsigned char data[MAXSIZE];
unsigned char energy[MAXSIZE];
unsigned char calc[MAXSIZE];
unsigned char bitmapdata[MAXSIZE*4];

wxMenuItem* wallsCB;
wxMenuItem* sourcesCB;
wxMenuItem* drawCB;
wxMenuItem* gravityCB;
wxMenuItem* interactionsCB;
wxMenuItem* limitCB;

bool doWalls;
bool doSources;
bool doDraw;
bool doGravity;
bool doInteractions;
bool doLimit;
bool doPause;
bool doRun;

bool drawAll;
wxString sandboxFilename;
wxString physicsFilename;
wxTreeCtrl* penSelections;
wxTreeItemId penSelectionIds[MAXNUMBEROFELEMENTS];
wxTimer* g_timer;
wxTimer* g_timer_second;
bool mouseIsDown;
int mousex, mousey;
int lastmousex, lastmousey;
unsigned char sand_type;
int pen_width;
wxStatusBar* statusbar;
double previous_now;
int g_width;
int g_height;

wxDateTime startTime;
int frameCount;

Canvas::Canvas(wxWindow* parent, wxWindowID id = -1, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize) : wxWindow( parent, id, pos, size, wxCLIP_CHILDREN ){
  g_canvas = this;

  this->SetSizeHints(g_width,g_height,g_width,g_height);
  this->SetBackgroundColour(wxColor(_("BLACK")));
  sand_type = 1;
  pen_width = 16;
  drawAll = true;

  memset(data, 0, g_width*g_height*sizeof(unsigned char));
  memset(energy, 0, g_width*g_height*sizeof(unsigned char));
  memset(calc, false, g_width*g_height*sizeof(unsigned char));

}



void drawCircle(int centerx, int centery){
  int r = pen_width/2;
  int rr = r*r;
  for(int dx=-r;dx<=r;++dx){
    int x = centerx+dx;
    int dy = (int)round(sqrt(rr - dx*dx));
    for(int y=centery-dy;y<=centery+dy;++y){
      if (x > 0 && x < g_width-1 && y > 0 && y < g_height-1){
	int center = (g_width*y)+x;
	data[center] = sand_type;
	energy[center] = 0;
	drawData(center);
      }
    }
  }
}


void calculate(){

  if (doPause == true){
    return;
  }

  ++frameCount;

  if (doSources){
    int space = g_width/(numberOfSources+1);

    for(int i=0;i<10;++i){
      if (rand() < RAND_MAX/4){
	for(int n=0;n<numberOfSources;++n){
	  data[g_width+(space*(n+1))+i] = (unsigned char)sources[n];
	  energy[g_width+(space*(n+1))+i] = 0;
	}
      }
    }
  }
  

  
  if (mouseIsDown){
    drawCircle(mousex, mousey);
  }


  for(int y=g_height-2;y>0;--y){

    int sx = 1;
    int ex = g_width-1;
    int dx = 1;
    if (rand() < 0.5*RAND_MAX){
      sx = g_width-2;
      ex = 1;
      dx = -1;
    }

    for(int x=sx;x!=ex;x+=dx){

      int center = (g_width*y)+x;
 
      if (data[center] == 0)
	continue;
      if (calc[center])
	continue;
    
      if (death_prob[data[center]][energy[center]] > 0){
	if (rand() < cdeath_prob[data[center]][energy[center]]){
	  int r = (int)round(99.0*(double(rand())/double(RAND_MAX)));
	  data[center] = death_center[data[center]][r];
	  energy[center] = 0;
	  drawData(center);
	  continue;
	}
      }
      
      
      if (conductivity[data[center]] > 1.0){
	int e = (int)energy[center] + (int)(99.0*(conductivity[data[center]]-1.0));
	if (e > 99)
	  e = 99;
	energy[center] = (char)e;
      }
      
      int left = center-1;
      int right = center+1;
      int up = center - g_width;
      int down = center + g_width;
      int downleft = center + g_width - 1;
      int downright = center + g_width + 1;
      int upleft = center - g_width - 1;
      int upright = center - g_width + 1;
    
      if (doInteractions){
	//Check for specific transformations.
	//Randomly check neighbors.

	int r = (int)round(47.0*double(rand())/RAND_MAX);
	switch(r){
	case(0):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(1):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(2):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(3):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(4):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(5):
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(6):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(7):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(8):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(9):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(10):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(11):
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(12):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(13):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(14):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  break;
	case(15):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(16):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(17):
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(18):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(19):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(20):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  break;
	case(21):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(22):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, up, x, y, x, y-1)
	  checkForTransformation(center, down, x, y, x, y+1)
	  break;
	case(23):
	  checkForTransformation(center, right, x, y, x+1, y)
	  checkForTransformation(center, left, x, y, x-1, y)
	  checkForTransformation(center, down, x, y, x, y+1)
	  checkForTransformation(center, up, x, y, x, y-1)
	  break;
	case(24):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(25):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(26):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(27):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(28):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(29):
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(30):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(31):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(32):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(33):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	case(34):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(35):
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	case(36):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(37):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(38):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  break;
	case(39):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	case(40):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(41):
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	case(42):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(43):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(44):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  break;
	case(45):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	case(46):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  break;
	case(47):
	  checkForTransformation(center, upright, x, y, x+1, y-1)
	  checkForTransformation(center, downright, x, y, x+1, y+1)
	  checkForTransformation(center, downleft, x, y, x-1, y+1)
	  checkForTransformation(center, upleft, x, y, x-1, y-1)
	  break;
	}
      }  
    
    
    
      if (doGravity){
      
	if (gravity[data[center]] == 0)
	  continue;

	//gravity > 0

	//falling down
	//density down
	//falling downleft
	//density downleft
	//falling downright
	//density downright
	
	//gravity < 0

	//up
	//upleft
	//upright


	//left open
	//left pushing
	//left density

	//right open
	//right pushing
	//right density


	if (gravity[data[center]] > 0){
	  //Check down
	  //falling
	  if (!doWalls || y < g_height-2){
	    if (data[down] == 0){
	      if (rand() < cgravity[data[center]]){
		found(center, down, x, y, x, y+1);
		continue;
	      }
	    }
	    else{
	      //density
	      if (density[data[center]] > density[data[down]]){
		if (rand() < ccogravitydensity[data[center]][data[down]] ){
		  found(center, down, x, y, x, y+1);
		  continue;
		}
	      }
	    }
	  }

	  if (rand() < 0.5*RAND_MAX){ //left versus right.
	    if (!doWalls || (y < g_height-2 && x > 1)){
	      //Check down and left
	      //falling
	      if (data[downleft] == 0){
		if (data[down] == 0){//no friction.
		  if (rand() < cgravity[data[center]]){
		    found(center, downleft, x, y, x-1, y+1);
		    continue;
		  }
		}
		else{
		  if (rand() < ccogravityslip[data[center]][data[down]]){
		    found(center, downleft, x, y, x-1, y+1);
		    continue;
		  }
		}
	      }
	      else{
		//density
		if (density[data[center]] > density[data[downleft]]){
		  if ( rand() < ccogravitydensity[data[center]][data[downleft]] ){
		    found(center, downleft, x, y, x-1, y+1);
		    continue;
		  }
		}
	      }
	    }
	  }
	  else{//left versus right.
	    if (!doWalls || (y < g_height-2 && x < g_width-2)){
	      //Check down and right
	      //falling
	      if (data[downright] == 0){
		if (data[down] == 0){//no friction.
		  if (rand() < cgravity[data[center]]){
		    found(center, downright, x, y, x+1, y+1);
		    continue;
		  }
		}
		else{
		  if (rand() < ccogravityslip[data[center]][data[down]]){
		    found(center, downright, x, y, x+1, y+1);
		    continue;
		  }
		}
	      }
	      else{
		//density
		if (density[data[center]] > density[data[downright]]){
		  if ( rand() < ccogravitydensity[data[center]][data[downright]] ){
		    found(center, downright, x, y, x+1, y+1);
		    continue;
		  }
		}
	      }
	    }
	  }
	}
	else{
	  //gravity < 0

	  //up or to the side?
	  if (rand() < 0.7*RAND_MAX){
	    if (!doWalls || y > 1){
	      //Check up
	      if (data[up] == 0){
		if (rand() < -cgravity[data[center]]){
		  found(center, up, x, y, x, y-1);
		  continue;
		}
	      }
	    }
	  }
	  else{
	    //Check up and left.
	    if (rand() < 0.5*RAND_MAX){ //left versus right.
	      if (!doWalls || (y > 1 && x > 1)){
		//floating
		if (data[upleft] == 0){
		  if (rand() < -cgravity[data[center]]){
		    found(center, upleft, x, y, x-1, y-1);
		    continue;
		  }
		}
	      }
	    }
	    else{	   //left versus right.
	      if (!doWalls || (y > 1 && x < g_width-2)){
		//Check up and right.
		if (data[upright] == 0){
		  if (rand() < -cgravity[data[center]]){
		    found(center, upright, x, y, x+1, y-1);
		    continue;
		  }
		}
	      }
	    }
	  }
	}

    
	if (rand() < 0.5*RAND_MAX){ //left versus right.
	  //Check left.
	  if (!doWalls || x > 1){
	    //Random opening.
	    if (data[left] == 0){
	      if (rand() < ccoslip[data[center]][data[center]]){
		found(center, left, x, y, x-1, y);
		continue;
	      }
	      
	      //Check again for being pushed to the side.
	      if (data[right] > 0){
		if (rand() < ccoslip[data[center]][data[center]]){
		  found(center, left, x, y, x-1, y);
		  continue;
		}
	      }
	    }
	    
	    //density
	    if (density[data[center]] > density[data[left]]){
	      if ( rand() < ccodensityslip[data[center]][data[left]] ){
		found(center, left, x, y, x-1, y);
		continue;
	      }
	    }
	  }
	}
	else{
	  //Check right.
	  if (!doWalls || x < g_width-2){
	    //Random opening.
	    if (data[right] == 0){
	      if (rand() < ccoslip[data[center]][data[center]]){
		found(center, right, x, y, x+1, y);
		continue;
	      }
	      
	      //Check again for being pushed to the side.
	      if (data[left] > 0){
		if (rand() < ccoslip[data[center]][data[center]]){
		  found(center, right, x, y, x+1, y);
		  continue;
		}
	      }
	    }
	    
	    //density
	    if (density[data[center]] > density[data[right]]){
	      if ( rand() < ccodensityslip[data[center]][data[right]] ){
		found(center, right, x, y, x+1, y);
		continue;
	      }
	    }
	  }
	}


      }
    }
  }

  int bottom = (g_height-1)*g_width;
  for(int x=0;x<g_width;++x){
    data[x]          = 0;
    data[bottom+x]   = 0;
    energy[x]        = 0;
    energy[bottom+x] = 0;
    drawData(x);
    drawData(bottom+x);
  }

  for(int y=0;y<g_height-1;++y){
    int leftside = y*g_width;
    int rightside = (y*g_width)+g_width-1;

    data[leftside]    = 0;
    data[rightside]   = 0;
    energy[leftside]  = 0;
    energy[rightside] = 0;
    drawData(leftside);
    drawData(rightside);
  }
  

  memset(calc, false, g_width*g_height*sizeof(unsigned char));

}


void Canvas::Refresh(){

  wxString str(_(""));
  str.Printf(_("%s [%d]"), names[data[(g_width*mousey)+mousex]].c_str(), (int)energy[(g_width*mousey)+mousex]);
  statusbar->SetStatusText(str, 2);


  if (doDraw){
    wxClientDC dc(this);
    dc.BeginDrawing();
    
    wxMemoryDC memdc;
    wxImage image(g_width, g_height, bitmapdata, true);
    wxBitmap bmp(image);
    memdc.SelectObject(bmp);
    dc.Blit(0,0,g_width, g_height, &memdc, 0, 0);
    
    if (!drawAll){
      dc.EndDrawing();
      return;
    }
    else{
      for(int center=0;center<g_width*g_height;++center){
	bitmapdata[(center*3)+0] = colors[data[center]][energy[center]].Red();
	bitmapdata[(center*3)+1] = colors[data[center]][energy[center]].Green();
	bitmapdata[(center*3)+2] = colors[data[center]][energy[center]].Blue();
      }
      drawAll = false;
    }

    dc.EndDrawing();
  }

}

void Canvas::OnTimer(wxTimerEvent& event){
  calculate();
  g_canvas->Refresh();
}

void Canvas::OnSecondTimer(wxTimerEvent& event){
  wxString str(_(""));
  str.Printf(_("%d fps"), frameCount);
  frameCount = 0;
  statusbar->SetStatusText(str,0);

  wxString str2(_(""));
  str2.Printf(_("%02d:%02d"), wxDateTime::Now().Subtract(startTime).GetHours(), 
	     wxDateTime::Now().Subtract(startTime).GetMinutes());
  statusbar->SetStatusText(str2,1);
}

void Canvas::OnEraseBG(wxEraseEvent& e){
  //Do absolutely nothing, thereby halting this event.
  //drawAll = true;
  //this->Refresh();
}

void drawLine(int x2, int y2, int x1, int y1){
  int dx = x1 - x2;
  int dy = y1 - y2;

  int t_max = abs(dx);
  if (abs(dy) > abs(dx))
    t_max = abs(dy);

  if (t_max == 0){
    drawCircle(x1, y1);
  }
  else{
    double ddx = double(dx)/double(t_max);
    double ddy = double(dy)/double(t_max);
    
    double x=x2;
    double y=y2;
    for(int t=0;t<=t_max;++t){
      drawCircle((int)round(x),(int)round(y));
      x += ddx;
      y += ddy;
    }
  }
}

void Canvas::OnMouseLeftDown(wxMouseEvent& event){
  mouseIsDown = true;
  mousex = event.GetX();
  mousey = event.GetY();
  lastmousex = mousex;
  lastmousey = mousey;

  drawCircle(mousex, mousey);
}

void Canvas::OnMouseLeftUp(wxMouseEvent& event){
  mouseIsDown = false;
}


void Canvas::OnMouseRightDown(wxMouseEvent& event){
  mousex = event.GetX();
  mousey = event.GetY();
  
  drawLine(lastmousex, lastmousey, mousex, mousey);

  lastmousex = mousex;
  lastmousey = mousey;
}

void Canvas::OnMouseMove(wxMouseEvent& event){
  if (event.LeftIsDown()){
    mousex = event.GetX();
    mousey = event.GetY();

    drawLine(lastmousex, lastmousey, mousex, mousey);

    lastmousex = mousex;
    lastmousey = mousey;
  }
  else{
    mousex = event.GetX();
    mousey = event.GetY();
    
    mouseIsDown = false;

    wxString str("");
    str.Printf(_("%s [%d]"), names[data[(g_width*mousey)+mousex]].c_str(), (int)energy[(g_width*mousey)+mousex]);
    statusbar->SetStatusText(str, 2);
  }
}

void Canvas::OnPaint(wxPaintEvent& event){
  drawAll = true;
  this->Refresh();
}


bool OnNew(wxWindow* window){
  //New
  wxString choices[] = {_("320x240 (fastest)"), _("640x480"), _("800x600"), _("1024x768"), _("1280x1024 (slowest)")};
  wxSingleChoiceDialog dialog(NULL, _("Select an area size"), _("New"), 5, choices, NULL);
  
  if (dialog.ShowModal() == wxID_OK){
    if (dialog.GetSelection() == 0){
      g_width = 320;
      g_height = 240;
    }
    else if (dialog.GetSelection() == 1){
      g_width = 640;
      g_height = 480;
    }
    else if (dialog.GetSelection() == 2){
      g_width = 800;
      g_height = 600;
    }
    else if (dialog.GetSelection() == 3){
      g_width = 1024;
      g_height = 768;
    }
    else if (dialog.GetSelection() == 4){
      g_width = 1280;
      g_height = 1024;
    }
    return true;
  }
  return false;
}


void RefreshPenList(){
  penSelections->DeleteAllItems();
  wxTreeItemId root = penSelections->AddRoot(_("Elements"));

  wxTreeItemId miscid = -1;
  for(int j=0;j<numberOfElements;++j){
    if (groups[j] == -1){
      if (visible[j]){
	if (miscid == wxTreeItemId(-1))
	  miscid = penSelections->AppendItem(root, "Misc");
	penSelectionIds[j] = penSelections->AppendItem(miscid, names[j]);
      }
    }
  }

  for(int i=0;i<numberOfGroups;++i){
    wxTreeItemId id2 = penSelections->AppendItem(root, groupNames[i]);
    for(int j=0;j<numberOfElements;++j){
      if (visible[j]){
	if (groups[j] == i)
	  penSelectionIds[j] = penSelections->AppendItem(id2, names[j]);
      }
    }
  }

  penSelections->SelectItem(penSelectionIds[0]);
  sand_type = 0;
}


MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, 
		     long style) : wxFrame(NULL, -1, title, pos, size, style){
  g_mainFrame = this;

  wxMenu* fileMenu = new wxMenu;
  wxMenu* optionsMenu = new wxMenu;
  wxMenu* helpMenu = new wxMenu;
  
  fileMenu->Append(1050, _("New.."), _(""));
  fileMenu->AppendSeparator();
  fileMenu->Append(1051, _("Load sandbox.."), _(""));
  fileMenu->Append(1052, _("Save sandbox.."), _(""));
  fileMenu->AppendSeparator();
  fileMenu->Append(1055, _("Load physics.."), _(""));
  fileMenu->Append(1056, _("Save physics.."), _(""));
  fileMenu->AppendSeparator();
  fileMenu->Append(1053, _("Exit"), _(""));

  wallsCB = new wxMenuItem(optionsMenu, 1002, _("Boundary Walls"), _(""), wxITEM_CHECK);
  sourcesCB = new wxMenuItem(optionsMenu, 1003, _("Sources"), _(""), wxITEM_CHECK);
  drawCB = new wxMenuItem(optionsMenu, 1004, _("Paint Updates"), _(""), wxITEM_CHECK);
  gravityCB = new wxMenuItem(optionsMenu, 1005, _("Gravity"), _(""), wxITEM_CHECK);
  interactionsCB = new wxMenuItem(optionsMenu, 1006, _("Element Interactions"), _(""), wxITEM_CHECK);
  limitCB = new wxMenuItem(optionsMenu, 1007, _("Limit FPS"), _(""), wxITEM_CHECK);

  optionsMenu->Append(wallsCB);
  optionsMenu->Append(sourcesCB);
  optionsMenu->Append(drawCB);
  optionsMenu->Append(gravityCB);
  optionsMenu->Append(interactionsCB);
  optionsMenu->Append(limitCB);

  helpMenu->Append(1054, _("About"), _(""));

  wxMenuBar* menuBar = new wxMenuBar();
  menuBar->Append(fileMenu, _("File"));
  menuBar->Append(optionsMenu, _("Options"));
  menuBar->Append(helpMenu, _("Help"));

  SetMenuBar(menuBar);

  wallsCB->Check();
  sourcesCB->Check();
  drawCB->Check();
  gravityCB->Check();
  interactionsCB->Check();
  limitCB->Check();

  doWalls = wallsCB->IsChecked();
  doSources = sourcesCB->IsChecked();
  doDraw = drawCB->IsChecked();
  doGravity = gravityCB->IsChecked();
  doInteractions = interactionsCB->IsChecked();
  doLimit = limitCB->IsChecked();

  statusbar = this->CreateStatusBar();
  statusbar->SetFieldsCount(3);
  statusbar->Show(true);

  g_canvas = new Canvas(this, -1, wxDefaultPosition, wxSize(g_width, g_height));
  
  wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
  {
    wxBoxSizer* RHSizer = new wxBoxSizer(wxVERTICAL);
    {
      wxFlexGridSizer* RH1 = new wxFlexGridSizer(2);
      {
	const wxString labels2[10] = {_("1"), _("2"), _("4"), _("8"), _("16"), _("32"), _("64"), _("128"), _("256"), _("512")};

	penSelections = new wxTreeCtrl(this, 1000, wxDefaultPosition, wxSize(200,500), wxTR_HAS_BUTTONS | wxTR_SINGLE);
	wxListBox* lb= new wxListBox(this, 1001, wxDefaultPosition, wxDefaultSize, 10, labels2, wxLB_SINGLE);
	lb->SetSelection(4);
      
	RH1->Add(new wxStaticText(this, -1, _("")));
	RH1->Add(new wxStaticText(this, -1, _("Pen Size")));
	RH1->Add(penSelections, 1, wxEXPAND);
	RH1->Add(lb, 0, wxEXPAND);
      }
      wxBoxSizer* RH2 = new wxBoxSizer(wxHORIZONTAL);
      {
	RH2->Add(new wxBitmapButton(this, 1025, wxBitmap(refresh_xpm)), 0, wxCENTER | wxALL, 10);
	RH2->Add(new wxBitmapButton(this, 1026, wxBitmap(pause_xpm)), 0, wxCENTER | wxALL, 10);

      }
      RHSizer->Add(RH2, 0);
      RHSizer->Add(RH1, 1);
    }

    sizer->Add(g_canvas, 0, wxADJUST_MINSIZE|wxALL, 10);
    sizer->Add(RHSizer, 0);
  }
  this->SetSizer(sizer);
  
  this->Layout();
  sizer->Fit(this);

  g_timer = new wxTimer(g_canvas, 999);
  g_timer->Start(TIMERINTERVAL);

  g_timer_second = new wxTimer(g_canvas, 998);
  g_timer_second->Start(1000);

}

void loadSandbox(wxString filename){
  wxImage loadBitmap;
  loadBitmap.LoadFile(filename);
  g_width = loadBitmap.GetWidth();
  g_height = loadBitmap.GetHeight();
  drawAll = true;

  for(int y=0;y<g_height;++y){
    for(int x=0;x<g_width;++x){
      int i = (y*g_width)+x;
      
      data[i] = 0;
      
      //Find the closest.
      unsigned int smallestDistance = 256+256+256;
      
      unsigned char red = loadBitmap.GetRed(x,y);
      unsigned char green = loadBitmap.GetGreen(x,y);
      unsigned char blue = loadBitmap.GetBlue(x,y);
      
      if (red == 0 && green == 0 && blue == 0)
	continue;
      
      for(int j=0;j<numberOfElements;++j){
	if (j == 8)
	  continue;
	unsigned int dist = 
	  int(abs(red - colors[j][0].Red())) + 
	  int(abs(green - colors[j][0].Green())) + 
	  int(abs(blue - colors[j][0].Blue()));
	if (dist < smallestDistance){
	  smallestDistance = dist;
	  data[i] = j;
	}
      }
    }
  }
  
  g_canvas->SetSizeHints(g_width,g_height,g_width,g_height);
  //g_canvas->SetClientSize(g_width,g_height);
  g_mainFrame->Layout();
  g_mainFrame->GetSizer()->Fit(g_mainFrame);

}


void loadFileError(int lineNumber, const wxString message){
  wxString str(_(""));
  str << "Error on line " << lineNumber << ". " << message;

  wxMessageDialog dlg(g_mainFrame, str, _("Error"), wxOK);
  dlg.ShowModal();

  for(int i=0;i<MAXNUMBEROFELEMENTS;++i){
    groups[i] = -1;
    conductivity[i] = 0;
    visible[i] = 0;

    for(int j=0;j<MAXNUMBEROFELEMENTS;++j){
      for(int k=0;k<100;++k){
	trans_center[i][j][k] = 0;
	trans_neighbor[i][j][k] = 0;
	death_center[i][k] = 0;
	
	colors[i][k] = wxColor(0,0,0);
	trans_prob[i][j][k] = 0;
	ctrans_prob[i][j][k] = 0;
	death_prob[i][k] = 0;
	cdeath_prob[i][k] = 0;
    
      }
    }
  }

  numberOfGroups = 0;
  numberOfElements = 0;

  memset(data, 0, g_width*g_height*sizeof(unsigned char));
  memset(energy, 0, g_width*g_height*sizeof(unsigned char));
}


void loadPhysics(wxString filename){

  for(int i=0;i<MAXNUMBEROFELEMENTS;++i){
    sources[i] = -1;
    groups[i] = -1;
    conductivity[i] = 0;
    visible[i] = 1;

    for(int j=0;j<MAXNUMBEROFELEMENTS;++j){
      for(int k=0;k<100;++k){
	trans_center[i][j][k] = 0;
	trans_neighbor[i][j][k] = 0;
	death_center[i][k] = 0;

	colors[i][k] = wxColor(0,0,0);
	trans_prob[i][j][k] = 0;
	ctrans_prob[i][j][k] = 0;
	death_prob[i][k] = 0;
	cdeath_prob[i][k] = 0;
      }
    }
  }

  numberOfGroups = 0;
  numberOfElements = 0;
  numberOfSources = 0;

  FILE* file = fopen(filename, "r");
  if (file == NULL){
    loadFileError(0, _("Could not open file."));
    return;
  }

  char line[200];

  //First, find out what version of file this is.
  int version = 0;
  while(fgets(line, 200, file) != NULL){
    if (line[0] == '#'){
      if (strstr(line, "subversion 1") != NULL)
	version = 1;
      else if (strstr(line, "subversion 2") != NULL)
	version = 2;
    }
  }

  if (version == 0){
    loadFileError(0, _("Could not find a line that says \"subversion #\"."));
    fclose(file);
    return;
  }

  rewind(file);
  

  if (version == 1){
    int state = 0;//0=between elements, 1=have read an element.
    numberOfElements = 0;
    while(fgets(line, 200, file) != NULL){
      if (line[0] == '#'){
	//skip. comment.
      }
      else if (line[0] == ' ' || line[0] == '\t' || line[0] == '\n' || line[0] == '\r'){
	//Empty line.
	state = 0;
      }
      else{
	if (state == 0){
	  char name[128];
	  sscanf(line, "%s\t", name);
	  names[numberOfElements] = wxString(name);
	  ++numberOfElements;
	  state = 1;
	}
	else{
	  //Just skip for now.
	}
      }
    }
      
    rewind(file);
    state = 0;
    int elementNumber = -1;
    while(fgets(line, 200, file) != NULL){
      if (line[0] == '#'){
	//skip. comment.
      }
      else if (line[0] == ' ' || line[0] == '\t' || line[0] == '\n' || line[0] == '\r'){
	//Empty line.
	state = 0;
      }
      else{
	if (state == 0){
	  ++elementNumber;
	  char name[128];
	  int red, green, blue;
	  char deathname[128];
	  float d,s,g,dr;
	    
	  sscanf(line, "%s\t%d\t%d\t%d\t%f\t%f\t%f\t%s\t%f", 
		 &name, &red, &green, &blue, 
		 &d, &s, &g, 
		 &deathname, &dr);
	    
	  density[elementNumber] = (double)d;
	  slip[elementNumber] = (double)s;
	  gravity[elementNumber] = (double)g;
	
	  for(int i=0;i<numberOfElements;++i){
	    if (wxString(deathname) == names[i]){
	      for (int k=0;k<100;++k){
		death_center[elementNumber][k] = i;
		death_prob[elementNumber][k] = (double)dr;
		colors[elementNumber][k] = wxColour((unsigned char)(red+(double(k)/100.0)*(255-red)), 
						    (unsigned char)(green+(double(k)/100.0)*(255-green)), 
						    (unsigned char)(blue+(double(k)/100.0)*(255-blue)));
	      }
	    }
	  }
	
	  state = 1;
	}
	else{
	  //Reading element interactions.
	  char neighbor[128];
	  char to[128];
	  char from[128];
	  float prob = 0;
	    
	  sscanf(line, "%s\t%s\t%s\t%f", &neighbor, &to, &from, &prob);
	    
	  int n_neighbor = -1;
	  int n_to = -1;
	  int n_from = -1;
	  for(int i=0;i<numberOfElements;++i){
	    if (names[i] == wxString(neighbor))
	      n_neighbor = i;
	    if (names[i] == wxString(to))
	      n_to = i;
	    if (names[i] == wxString(from))
	      n_from = i;
	  }
	    
	  if (n_neighbor != -1 && n_to != -1 && n_from != -1){
	    for(int k=0;k<100;++k){
	      trans_center[elementNumber][n_neighbor][k] = n_to;
	      trans_neighbor[elementNumber][n_neighbor][k] = n_from;
	      trans_prob[elementNumber][n_neighbor][k] = (double)prob;
	    }
	  }
	}
      }
    }
  }
  else if (version == 2){
    //Then, count the number of elements and get their names.
    numberOfGroups = 0;
    numberOfElements = 0;
    while(fgets(line, 200, file) != NULL){
      if (line[0] == '#' || line[0] == ' ' || line[0] == '\t' || line[0] == '\n' || line[0] == '\r'){
	//skip.
      }
      else{
	char* type = strtok(line, " \t\n\r");
	if (strcmp(type, "element") == 0){
	  char* name = strtok(NULL, " \t\n\r");
	  names[numberOfElements] = wxString(name);
	  ++numberOfElements;
	}
	else if (strcmp(type, "group") == 0){
	  char* name = strtok(NULL, " \t\n\r");
	  groupNames[numberOfGroups] = wxString(name);
	  ++numberOfGroups;
	}
      }
    }
    
    numberOfSources = 0;
    rewind(file);
    
    //Now fill in the elements.
    int elementNumber = 0;
    int lineNumber = 0;
    while(fgets(line, 200, file) != NULL){
      ++lineNumber;
      if (line[0] == '#' || line[0] == ' ' || line[0] == '\t' || line[0] == '\n' || line[0] == '\r'){
	//skip.
      }
      else{
	char type[128];
	sscanf(line, "%s", type);
	
	if (strcmp(type, "element") == 0){
	  char name[128];
	  int red;
	  int green;
	  int blue;
	  float g,s,d,c;
	  int v;
	  
	  sscanf(line, "%s%s%d%d%d%f%f%f%f%d", 
		 &type, &name, &red, &green, &blue, 
		 &g, &s, &d, &c, &v);
	  
	  gravity[elementNumber] = (double)g;
	  slip[elementNumber] = (double)s;
	  density[elementNumber] = (double)d;
	  conductivity[elementNumber] = (double)c;
	  visible[elementNumber] = (bool)v;

	  for(int k=0;k<100;++k){
	    colors[elementNumber][k] = wxColour((unsigned char)(red+(double(k)/100.0)*(255-red)), 
						(unsigned char)(green+(double(k)/100.0)*(255-green)), 
						(unsigned char)(blue+(double(k)/100.0)*(255-blue)));
	  }

	  ++elementNumber;
	}
	else if (strcmp(type, "sources") == 0){
	  char* gar = strtok(line, " \t\n\r");

	  char* element = strtok(NULL, " \t\n\r");
	  if (element == NULL){
	    loadFileError(lineNumber, _("Invalid sources line. Need at least 1 element in the group."));
	    fclose(file);
	    return;
	  }

	  while(element != NULL){
	    int n_element = -1;
	    for(int i=0;i<numberOfElements;++i){
	      if (names[i] == wxString(element))
		n_element = i;
	    }

	    if (n_element == -1){
	      loadFileError(lineNumber, _("Invalid sources line. Unknown element."));
	      fclose(file);
	      return;
	    }

	    sources[numberOfSources] = n_element;
	    ++numberOfSources;
	    element = strtok(NULL, " \t\n\r");
	  }
	  
	}
	else if (strcmp(type, "group") == 0){
	  char* gar = strtok(line, " \t\n\r");
	  char* group = strtok(NULL, " \t\n\r");

	  if (gar == NULL || group == NULL){
	    loadFileError(lineNumber, _("Invalid group line."));
	    fclose(file);
	    return;
	  }

	  int n_group = -1;
	  for(int i=0;i<numberOfGroups;++i){
	    if (groupNames[i] == wxString(group))
	      n_group = i;
	  }
	  
	  char* element = strtok(NULL, " \t\n\r");

	  if (element == NULL){
	    loadFileError(lineNumber, _("Invalid group line. Need at least 1 element in the group."));
	    fclose(file);
	    return;
	  }

	  while(element != NULL){
	    int n_element = -1;
	    for(int i=0;i<numberOfElements;++i){
	      if (names[i] == wxString(element))
		n_element = i;
	    }

	    if (n_element == -1){
	      loadFileError(lineNumber, _("Invalid group line. Unknown element."));
	      fclose(file);
	      return;
	    }

	    groups[n_element] = n_group;
	    element = strtok(NULL, " \t\n\r");
	  }
	  
	}
	else if (strcmp(type, "self") == 0){
	  //deathrate. "self [prob] [element] [prob][element] ..."
	  char* gar = strtok(line, " \t\n\r");
	  char* thisprob = strtok(NULL, " \t\n\r");
	  char* center = strtok(NULL, " \t\n\r");
	  
	  if (gar == NULL || thisprob == NULL || center == NULL){
	    loadFileError(lineNumber, _("Invalid self line."));
	    fclose(file);
	    return;
	  }

	  float n_thisprob = 0;
	  sscanf(thisprob, "%f", &n_thisprob);
	  
	  int n_center = -1;
	  for(int i=0;i<numberOfElements;++i){
	    if (names[i] == wxString(center))
	      n_center = i;
	  }
	  
	  if (n_center == -1){
	    loadFileError(lineNumber, _("Invalid self line. Unknown element."));
	    fclose(file);
	    return;
	  }

	  for(int i=0;i<100;++i)
	    death_prob[n_center][i] = (double)n_thisprob;
	  
	  char* prob = strtok(NULL, " \t\n\r");
	  
	  if (prob == NULL){
	    loadFileError(lineNumber, _("Invalid self line. Need at least 1 probability."));
	    fclose(file);
	    return;
	  }

	  int currentProbIndex = 0;
	  while(prob != NULL){
	    char* s_trans_center = strtok(NULL, " \t\n\r");
	    
	    if (s_trans_center == NULL){
	      loadFileError(lineNumber, _("Invalid self line. Need at least 1 element."));
	      fclose(file);
	      return;
	    }

	    float n_prob;
	    sscanf(prob, "%f", &n_prob);
	    
	    int n_trans_center = -1;
	    for(int i=0;i<numberOfElements;++i){
	      if (names[i] == wxString(s_trans_center))
		n_trans_center = i;
	    }
	    
	    if (n_trans_center == -1){
	      loadFileError(lineNumber, _("Invalid self line. Unknown element."));
	      fclose(file);
	      return;
	    }

	    //Fill the probability array.
	    for(int i=currentProbIndex; i < 100 && i < currentProbIndex + int(round(100.0*n_prob)); ++i){
	      death_center[n_center][i] = n_trans_center;
	    }
	    currentProbIndex = currentProbIndex + int(round(100.0*n_prob));
	      
	    prob = strtok(NULL, " \t\n\r");
	  }
	  
	  for(int i=currentProbIndex; i < 100;++i){
	    death_center[n_center][i] = n_center;
	  }
	}
	else if (strcmp(type, "neighbor") == 0){
	  //neighbor [prob] [element] [element] [prob][element][element] ...
	  //Reading element interactions.
	  char* gar = strtok(line, " \t\n\r");
	  char* thisprob = strtok(NULL, " \t\n\r");
	  char* center = strtok(NULL, " \t\n\r");
	  char* neighbor = strtok(NULL, " \t\n\r");
	
	  if (gar == NULL || thisprob == NULL || center == NULL || neighbor == NULL){
	    loadFileError(lineNumber, _("Invalid neighbor line."));
	    fclose(file);
	    return;
	  }

	  float n_thisprob = 0;
	  sscanf(thisprob, "%f", &n_thisprob);
	

	  int n_center = -1;
	  int n_neighbor = -1;
	  for(int i=0;i<numberOfElements;++i){
	    if (names[i] == wxString(center))
	      n_center = i;
	    if (names[i] == wxString(neighbor))
	      n_neighbor = i;
	  }

	  if (n_center == -1 || n_neighbor == -1){
	    loadFileError(lineNumber, _("Invalid neighbor line. Unknown element."));
	    fclose(file);
	    return;
	  }

	  for(int i=0;i<100;++i)
	    trans_prob[n_center][n_neighbor][i] = (double)n_thisprob;

	  char* prob = strtok(NULL, " \t\n\r");

	  if (prob == NULL){
	    loadFileError(lineNumber, _("Invalid neighbor line. Must have at least 1 probability."));
	    fclose(file);
	    return;
	  }

	  int currentProbIndex = 0;
	  while(prob != NULL){
	    char* s_trans_center = strtok(NULL, " \t\n\r");
	    char* s_trans_neighbor = strtok(NULL, " \t\n\r");

	    float n_prob;
	    sscanf(prob, "%f", &n_prob);
	
	    int n_trans_center = -1;
	    int n_trans_neighbor = -1;
	    for(int i=0;i<numberOfElements;++i){
	      if (names[i] == wxString(s_trans_center))
		n_trans_center = i;
	      if (names[i] == wxString(s_trans_neighbor))
		n_trans_neighbor = i;
	    }

	    if (n_trans_center == -1 || n_trans_neighbor == -1){
	      loadFileError(lineNumber, _("Invalid neighbor line. Unknown element."));
	      fclose(file);
	      return;
	    }

	    //Fill the probability array.
	    for(int i=currentProbIndex; i < 100 && i < currentProbIndex + int(round(100.0*n_prob)); ++i){
	      trans_center[n_center][n_neighbor][i] = n_trans_center;
	      trans_neighbor[n_center][n_neighbor][i] = n_trans_neighbor;
	    }
	    currentProbIndex = currentProbIndex + int(round(100.0*n_prob));
	  
	    prob = strtok(NULL, " \t\n\r");
	  }
	  if (currentProbIndex != 100){
	    loadFileError(lineNumber, _("Invalid neighbor line. All probabilities must add up to 1."));
	    fclose(file);
	    return;
	  }
	  
	}
	else{
	  loadFileError(lineNumber, _("Invalid line. Unrecognized keyword."));
	  fclose(file);
	  return;
	}

      }
    }
  
  }

  //Precalculate some commonly used probabilities.
  for(int i=0;i<numberOfElements;++i){
    cgravity[i] = (int)round(gravity[i]*RAND_MAX);
    for(int k=0;k<100;++k){
      cdeath_prob[i][k] = (int)round(death_prob[i][k]*RAND_MAX);
    }
    for(int j=0;j<numberOfElements;++j){
      ccoslip[i][j] = (int)round( ((slip[i]+slip[j])/2.0)*RAND_MAX );
      ccogravityslip[i][j] = (int)round( fabs(gravity[i])*((slip[i]+slip[j])/2.0)*RAND_MAX );
      ccogravitydensity[i][j] = (int)round( fabs(gravity[i])*fabs(density[i]-density[j])*RAND_MAX );
      ccodensityslip[i][j] = (int)round( fabs(density[i]-density[j])*((slip[i]+slip[j])/2.0)*RAND_MAX );
      //probability that these will switch places.
      //High difference = high prob. Low difference=low prob.
      ccodensity[i][j] = (int)round( fabs(density[i]-density[j])*RAND_MAX );

      for(int k=0;k<100;++k){
	ctrans_prob[i][j][k] = (int)round( trans_prob[i][j][k]*RAND_MAX);
      }
    }
  }

  
  //for(int i=0;i<numberOfElements;++i){
  //std::cout << "\n" << names[i] << "\n";
  //std::cout << "\n" << conductivity[i] << "\n";

    //for(int k=0;k<100;++k){
    //  std::cout << cdeath_prob[i][k] << " ";
    //}
  //}
  
  
  //Update selections.
  RefreshPenList();
  
  fclose(file);

}

void MainFrame::OnMenu(wxCommandEvent& event){

  if (event.GetId() == 1050){
    OnNew(this);

    drawAll = true;
    memset(data, 0, g_width*g_height*sizeof(unsigned char));
    memset(energy, 0, g_width*g_height*sizeof(unsigned char));

    g_canvas->SetSizeHints(g_width,g_height,g_width,g_height);
    //g_canvas->SetClientSize(g_width,g_height);
    g_mainFrame->Layout();
    g_mainFrame->GetSizer()->Fit(g_mainFrame);
    
    g_canvas->Refresh();
  }
  else if(event.GetId() == 1051){
    //Load
    wxFileDialog dialog(this, _("Load from a file"), _(""), _(""), _("Any Image Files (*.*)|*.*"), wxOPEN);
    
    if (dialog.ShowModal() == wxID_OK){
      sandboxFilename = dialog.GetPath();
      loadSandbox(sandboxFilename);
    }
  }
  else if(event.GetId() == 1052){
    //Save
    wxFileDialog dialog(this, _("Save to a file"), _(""), _(""), _("PNG files (*.png)|*.png|BMP files (*.bmp)|*.bmp"), wxSAVE);
    
    if (dialog.ShowModal() == wxID_OK){
      wxString filename = dialog.GetPath();
      
      for(int i=0;i<g_width*g_height;++i){
	bitmapdata[(i*3)] = colors[data[i]][0].Red();
	bitmapdata[(i*3)+1] = colors[data[i]][0].Green();
	bitmapdata[(i*3)+2] = colors[data[i]][0].Blue();
      }
      wxImage saveBitmap(g_width, g_height, bitmapdata, true);
      wxBitmap bmp(saveBitmap);

      if (dialog.GetFilterIndex() == 0 || filename.Find(_(".png")) != -1 || filename.Find(_(".PNG")) != -1){
	bmp.SaveFile(filename, wxBITMAP_TYPE_PNG);
      }
      else{
	bmp.SaveFile(filename, wxBITMAP_TYPE_BMP);
      }
    }
  }
  else if(event.GetId() == 1053){
    //Exit
    doRun = false;

    delete g_timer;
    delete g_timer_second;
 

    g_mainFrame->Close(true);
  }
  else if(event.GetId() == 1054){
    //About
    wxString str = "Owen Piette's Falling Sand Game\nCopyright Owen Piette 2006.\nThank you to Troy Larson for the refresh button idea.\n\n";
    str << "Version " << VERSION << "-" << CVERSION << "\n" << "Check for updates at:\nhttp://www.piettes.com/fallingsandgame/";
    wxMessageDialog dlg(this, str, _("About"));
    dlg.ShowModal();
  }
  else if(event.GetId() == 1055){
    //Load physics

    wxFileDialog dialog(this, _("Load from a file"), _(""), _(""), _("Physics Files (*.txt)|*.txt"), wxOPEN);
    if (dialog.ShowModal() == wxID_OK){
      physicsFilename = dialog.GetPath();
      loadPhysics(physicsFilename);
    }
  }
  else if(event.GetId() == 1056){
    //Save physics

    wxFileDialog dialog(this, _("Save to a file"), _(""), _(""), _("Physics files (*.txt)|*.txt"), wxSAVE);
    
    if (dialog.ShowModal() == wxID_OK){
      wxString filename = dialog.GetPath();
      FILE* file = fopen(filename, "w");

      fprintf(file, "#wxSand: Owen Piette's Falling Sand Game\n#Version %s-%s, File subversion 2\n", VERSION, CVERSION);
      
      //groups
      for(int i=0;i<numberOfGroups; ++i){
	fprintf(file, "group\t%s", groupNames[i].c_str());
	for(int j=0;j<numberOfElements;++j){
	  if (groups[j] == i){
	    fprintf(file, "\t%s", names[j].c_str());
	  }
	}
	fprintf(file, "\n");
      }

      //sources
      fprintf(file, "sources");
      for(int i=0;i<numberOfSources; ++i){
	fprintf(file, "\t%s", names[sources[i]].c_str());
      }
      fprintf(file, "\n");

      for(int i=0;i<numberOfElements;++i){
	//element
	fprintf(file, "element\t%s\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%d\n", 
		names[i].c_str(), colors[i][0].Red(), colors[i][0].Green(), colors[i][0].Blue(), 
		gravity[i], slip[i], density[i], conductivity[i], (int)visible[i]);

	//deathrate. "self [prob] [element] [prob][element] ..."
	if (death_prob[i] > 0){
	  fprintf(file, "self\t%f\t%s", death_prob[i][0], names[i].c_str());
	  int sum = 1;
	  int prev_index = death_center[i][0];
	  for(int k=1;k<100;++k){
	    if (prev_index == death_center[i][k]){
	      ++sum;
	    }
	    else{
	      fprintf(file, "\t%f\t%s", double(sum)/100.0, names[death_center[i][k-1]].c_str());
	      sum = 1;
	    }
	    prev_index = death_center[i][k];
	  }
	  fprintf(file, "\t%f\t%s", double(sum)/100.0, names[death_center[i][99]].c_str());

	  fprintf(file, "\n");
	}

	//Neighbors
	for(int j=0;j<numberOfElements;++j){
	  //neighbor [prob] [element] [element] [prob][element][element] ...
	  if (trans_prob[i][j] != 0){
	    fprintf(file, "neighbor\t%f\t%s\t%s", trans_prob[i][j][0], names[i].c_str(), names[j].c_str());
	    int sum = 1;
	    int prev_index = trans_center[i][j][0];
	    for(int k=1;k<100;++k){
	      if (prev_index == trans_center[i][j][k]){
		++sum;
	      }
	      else{
		fprintf(file, "\t%f\t%s\t%s", double(sum)/100.0, names[trans_center[i][j][k-1]].c_str(), 
			names[trans_neighbor[i][j][k-1]].c_str());
		sum = 1;
	      }
	      prev_index = trans_center[i][j][k];
	    }
	    fprintf(file, "\t%f\t%s\t%s", double(sum)/100.0, names[trans_center[i][j][99]].c_str(), 
		    names[trans_neighbor[i][j][99]].c_str());
	    fprintf(file, "\n");
	  }
	}
	
      }
      
      fprintf(file, "\n");
      fclose(file);
      
    }

  }

  doWalls = wallsCB->IsChecked();
  doSources = sourcesCB->IsChecked();
  doDraw = drawCB->IsChecked();
  doGravity = gravityCB->IsChecked();
  doInteractions = interactionsCB->IsChecked();
  doLimit = limitCB->IsChecked();

  if (doLimit){
    if (!(g_timer->IsRunning()))
      g_timer->Start(TIMERINTERVAL);
  }
  else
    if ((g_timer->IsRunning()))
      g_timer->Stop();
  
}

void MainFrame::OnButton(wxCommandEvent& event){
  if (event.GetId() == 1025){
    wxMessageDialog dlg(this, _("Are you certain?"), _("Refresh/Reload"), wxYES_NO);
    if (dlg.ShowModal() == wxID_YES){
      if(sandboxFilename == _("")){
	//Refresh
	drawAll = true;
	memset(data, 0, g_width*g_height*sizeof(unsigned char));
	memset(energy, 0, g_width*g_height*sizeof(unsigned char));
      }
      else{
	//reload
	loadSandbox(sandboxFilename);
      }
      
      if (physicsFilename != _("")){
	loadPhysics(physicsFilename);
      }
    }
  }
}

void MainFrame::OnToggleButton(wxCommandEvent& event){
  if (event.GetId() == 1026){
    if (doPause == false)
      doPause = true;
    else
      doPause = false;
  }
}

void MainFrame::OnElementChoice(wxTreeEvent& event){
  wxTreeItemId id = event.GetItem();

  for(int i=0;i<numberOfElements;++i){
    if (penSelectionIds[i] == id){
      sand_type = i;
    }
  }

}

void MainFrame::OnChoice(wxCommandEvent& event){
  pen_width = (int)(pow(2.0,event.GetSelection()));
}

void MainFrame::OnSize(wxSizeEvent& event){
  drawAll = true;
  g_mainFrame->Layout();
}

void MainFrame::OnMove(wxFocusEvent& event){
  drawAll = true;
  if (g_canvas){
    g_canvas->Refresh();
  }
}


bool DropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames){
  
  if (filenames[0].First(_(".txt")) != -1 || filenames[0].First(_(".TXT")) != -1 ){
    loadPhysics(filenames[0]);
  }
  else{
    loadSandbox(filenames[0]);
  }

  if (filenames.GetCount() == 2){
    if (filenames[1].First(_(".txt")) != -1 || filenames[1].First(_(".TXT")) != -1 ){
      loadPhysics(filenames[1]);
    }
    else{
      loadSandbox(filenames[1]);
    }
  }

  return true;
}


/* this is executed upon startup, like 'main()' in non-wxWidgets programs */
bool Sand::OnInit()
{
  g_mainFrame = NULL;
  g_canvas = NULL;
  mouseIsDown = false;
  statusbar = NULL;
  g_width = 640;
  g_height = 480;
  doPause = false;
  startTime = wxDateTime::Now();

  numberOfGroups = 0;
  numberOfElements = 17;
  numberOfSources = 0;


  wxString str = _("Owen Piette's Falling Sand Game");
  g_mainFrame = new MainFrame(str, wxDefaultPosition, wxDefaultSize);//, wxCLOSE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN);
  g_mainFrame->Show(TRUE);

  ::wxInitAllImageHandlers();

  sandboxFilename = _("");
  physicsFilename = _("");


  FILE* file = fopen("default.txt", "w");
  fprintf(file, defaultFileContents);
  fclose(file);

  if (this->argc > 1){
    if (wxString(argv[1]).First(_(".txt")) != -1 || wxString(argv[1]).First(_(".TXT")) != -1 ){
      physicsFilename = wxString(argv[1]);
      loadPhysics(physicsFilename);
    }
    else{
      sandboxFilename = wxString(argv[1]);
      loadSandbox(sandboxFilename);
    }
  }
  if (this->argc > 2){
    if (wxString(argv[2]).First(_(".txt")) != -1 || wxString(argv[2]).First(_(".TXT")) != -1 ){
      physicsFilename = wxString(argv[2]);
      loadPhysics(physicsFilename);
    }
    else{
      sandboxFilename = wxString(argv[2]);
      loadSandbox(sandboxFilename);
    }
  }

  if (physicsFilename == _("")){
    physicsFilename = _("default.txt");
    loadPhysics(physicsFilename);
  }

  g_mainFrame->SetDropTarget(new DropTarget());

  return true;
}



int Sand::MainLoop(void){
  doRun = true;
  while (doRun) {
    if (!doLimit){
      calculate();
      g_canvas->Refresh();
    }
    while (Pending())
      Dispatch();
  }

  return 1;
}
