/
area/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/network/console/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
src/net/sourceforge/pain/network/console/
src/net/sourceforge/pain/network/console/telnet/
src/net/sourceforge/pain/plugin/
src/net/sourceforge/pain/plugin/command/
src/net/sourceforge/pain/plugin/reset/
src/net/sourceforge/pain/plugin/shutdown/
src/net/sourceforge/pain/plugin/social/
src/net/sourceforge/pain/util/
tests/
tests/net/sourceforge/pain/db/data/
package net.sourceforge.pain;


import net.sourceforge.pain.network.console.*;
import net.sourceforge.pain.data.*;
import net.sourceforge.pain.data.prototype.*;
import net.sourceforge.pain.data.type.*;
import net.sourceforge.pain.db.*;
import net.sourceforge.pain.plugin.*;
import net.sourceforge.pain.util.*;

import java.util.*;


public class Launcher {

	public static void main(String[] args) throws Exception {
		initDb();
		loadWorld();
		loadAllWhatsLeft();
	}

	private static void initDb() throws Exception {
		PainDB db = new PainDB("pain.pdb");
		Core.setDB(db);
	}

	private static void loadWorld() throws Exception {
		PainDB db = Core.getDB();

		Log.info("loading World");
		World world = (World) db.getRoot();
		if (world == null) {
			if (!db.isDatabaseEmpty()) {
				throw new RuntimeException("database is not empty, but world instance not found!");
			}
			Log.debug("Empty database detected!, creating world!");
			world = DatabaseConstructor.createSmallFantasyWorld(db);//:)
			db.setRoot(world);
			Log.debug("World Created!");
		} else {
			Log.info("World instance found");
		}
		Core.setWorld(world);

		Log.info("flushing all startup fixes");
		db.flush();
		Log.info("Flushed OK!");
	}

	private static void loadAllWhatsLeft() throws Exception {
		Log.info("Creating plugin manager");
		PluginManager plm = new PluginManager(Core.getApplicationPath() + "/classes");
		plm.init();
		Core.setPluginManager(plm);
		Log.info("Creating plugin manager OK");

		checkSafeShutdown(); // checks if server was properly shutted down (mark all players as logged out snd so on..)

		Log.info("Creating console manager");
		Core.setConsoleManager(new ConsoleManager());
		Log.info("Creating console manager OK");

		Log.info("starting timer...");
		new Thread(Core.getTime()).start();
		Log.info("done!");
	}

	private static void checkSafeShutdown() throws Exception {
		Core.processEvent("CheckSafeShutdown", null);
	}


	public static final class DatabaseConstructor {

		private DatabaseConstructor() {
		};


		public static World createSmallFantasyWorld(final PainDB db) throws Exception {
			Log.info("Creating world !!");
			DbTransaction t = new DbTransaction() {
				public Object execute(Object[] params) throws Exception {
					World world = new World(db);

					world.setName("PAiN world");

					Race hr = (Race) ObjectFactory.create(Race.class);
					hr.setName("Human");
					world.getRaces().add(hr);

					Race dr = (Race) ObjectFactory.create(Race.class);
					dr.setName("Dwarf");
					world.getRaces().add(dr);

					Race er = (Race) ObjectFactory.create(Race.class);
					er.setName("Elf");
					world.getRaces().add(er);

					Log.info("Creating areas and rooms");

//					SpaceGroup sg = (SpaceGroup) ObjectFactory.create(SpaceGroup.class);
					ResetGroup rg = (ResetGroup) ObjectFactory.create(ResetGroup.class);
					rg.setGroupInfo("Initial Reset Group");
					rg.setGroupId("initial");
//					rg.setResetPeriod(Time.PULSE_PER_SCD * 15);
					rg.setResetPeriod(Time.PULSE_PER_MIN * 3);
					world.getResetGroupRegistry().registerResetGroup(rg);

//					PrototypeInfo prot = (PrototypeInfo) sg.addRole(PrototypeInfo.class);
//					prot.setVnum("area:1");
//					prot.setAuthor("PAiN engine");

					IndexedSpace indexedSpace = (IndexedSpace) ObjectFactory.create(IndexedSpace.class);
					indexedSpace.setSpaceUniqueId("initial");
					world.getIndexedSpacesRegistry().registerSpace(indexedSpace);
					Space space = indexedSpace.asSpace();
					PrototypeInfo prot = (PrototypeInfo) space.addRole(PrototypeInfo.class);

					space.setName("The Void");
					space.setDesc("You are suspended in cool electric space above a translucent plain.  You feel\n" +
					        "synesthesia invading your nerves and reshuffling your senses.  The sky is the\n" +
					        "same obsidian color as the ground and you can't find a horizon.");
					space.setCapacity(Integer.MAX_VALUE);

					world.setDefaultBirthSpace(space);

					prot.setVnum("room:1");
					prot.setName(space.getName());
					prot.setDesc("First room in the world.");
					prot.setAuthor("PAiN engine.");

					Log.info("Creating GOD");
					Player gp = (Player) ObjectFactory.create(Player.class);
					gp.setLogin("god");
					gp.setPassword("god");
					gp.setQuitSpace(space);
					gp.addRole(Builder.class);
					world.getPlayersRegistry().addPlayer(gp);
					Interactive gi = gp.asInteractive();
					gi.setName("God");
					gi.setDesc("God");
					gi.setTargetList(new String[]{"god", "creator"});
					addToSpace(space, gp.asLocated());
					Mobile m = (Mobile) gp.addRole(Mobile.class);
					m.setMaxMoves(1000);
					m.setMoves(1000);
					Equipped eq = (Equipped) gp.addRole(Equipped.class);
					Space inventory = (Space) ObjectFactory.create(Space.class);
					inventory.setCapacity(Integer.MAX_VALUE);
					inventory.setName("Inventory");
					inventory.setDesc("Inside inventory");
					eq.setInventory(inventory);

					// granting comands to 'god':
					Set granted = gp.getGrantedCommands();
					granted.add("_all"); // special keyword, all commands allowed

					Log.info("Creating thing!");
					Physical tp = (Physical) ObjectFactory.create(Physical.class);
					tp.setSize(10);
					tp.setWeight(20);
					tp.setAppearanceDesc("small stone");
					Interactive ti = tp.asInteractive();
					ti.setName("small stone");
					ti.setDesc("small stone");
					ti.setTargetList(new String[]{"stone", "small"});
					addToSpace(space, ti.asLocated());

					// create new player proto
					PrototypeInfo p = (PrototypeInfo) ObjectFactory.create(PrototypeInfo.class);
					p.setVnum("player");
					p.setName("New players prototype");
					p.setAuthor("god");

					LifeFormPrototype lfp = (LifeFormPrototype) p.addRole(LifeFormPrototype.class);
					lfp.setLifePointsDice(new Dice(10, 10, 10));
					lfp.setSex(LifeFormPrototype.SEX_EITHER);
					lfp.setRace(hr);

					PhysicalPrototype pp = (PhysicalPrototype) p.addRole(PhysicalPrototype.class);
					pp.setAppearanceDesc("You see nothing special about him");
					pp.setSize(1);
					pp.setWeight(1);

					ReceptivePrototype rp = (ReceptivePrototype) p.getRole(ReceptivePrototype.class);
					rp.setCanFeel(true);
					rp.setCanHear(true);
					rp.setCanSee(true);

					InteractivePrototype ip = (InteractivePrototype) p.getRole(InteractivePrototype.class);
					ip.setDesc("human");
					ip.setTargetList(new String[]{"man", "human", "creature"});

					MobilePrototype mp = (MobilePrototype) p.addRole(MobilePrototype.class);
					mp.setMovePointsDice(new Dice(10, 10, 50));

					EquippedPrototype eqp = (EquippedPrototype) p.addRole(EquippedPrototype.class);
					PrototypeInfo invInfo = (PrototypeInfo) ObjectFactory.create(PrototypeInfo.class);
					invInfo.setName("default inventory prototype");
					invInfo.setVnum("inventory0");
					SpacePrototype invProto = (SpacePrototype) invInfo.addRole(SpacePrototype.class);
					invProto.setSpaceName("Inventory");
					invProto.setSpaceDesc("");
					invProto.setCapacity(Integer.MAX_VALUE);
					eqp.setInventoryPrototype(invProto);

					world.getPrototypesRegistry().registerPrototype(invInfo);
					world.getPrototypesRegistry().registerPrototype(p);

					Log.info("world created!");
					return world;
				}

				/** Code snippet from RelocateFn.
				 *  We could not reference to this class
				 *  directly from core pacage because of it's dynamic reloading nature
				 */
				public void addToSpace(Space space, Located obj) {
					Located first = space.getFirstInSpace();
					if (first != null) {
						final Located prev = first.getPrevInSpace(); // last in list
						prev.setNextInSpace(obj);
						obj.setPrevInSpace(prev);
					} else {
						space.setFirstInSpace(obj);
						first = obj;
					}
					first.setPrevInSpace(obj);  //backward list should be without nulls!
					obj.setNextInSpace(null); // forward list finished on null!
					obj.setLocation(space);
				}

			};
			return (World) db.execute(t);
		}
	}
}