////////////////////////////////////////////////////////////////
//
// CGM(Climbing Gym map)
//

var CGM = {
    defClass: function (obj) {
        function cls() {
            this.initialize.apply(this, arguments); // rule
        }
        CGM.addMethods(cls, obj);
        CGM.addMethods(cls, CGM.Mixin);
        return cls;
    },
    addMethods: function (cls, mixin) {
        for (var func in mixin) {
            if (! cls.prototype[func]) {
                cls.prototype[func] = mixin[func];
            }
        }
    }
};

CGM.Mixin = {
    _$:  function (id)  { return document.getElementById(id); },
    _$C: function (tag) { return document.createElement(tag); },
    _$T: function (txt) { return document.createTextNode(txt); },
    _setHandler: (function() {
	if (addEventListener) {
            return function(el, type, func) {
		el.addEventListener(type, func, false);
            };
	}
	if (attachEvent) {
            return function(el, type, func) {
		el.attachEvent('on' + type, function() {
                    func.call(el, window.event);
		});
            };
	}
	return function(el, type, func) {
            el['on' + type] = func;
	};
    })()
};

////////////////////////////////////////////////////////////////
//
//
//

CGM.opt = { lat:  36.0
          , lng:  138.50000
          , zoom: 7
          , mapTypeId: google.maps.MapTypeId.ROADMAP
          , map_id: 'map'
          , menu_id: 'menu'
          };

CGM.load = function () {
    var map = new CGM.Map(CGM.opt);
    map.display();
    var gyms = new CGM.Gyms(CGM.DB, map);
    gyms.display();
    var menu = new CGM.Menu(CGM.opt, gyms);
    menu.display();
};

////////////////////////////////////////////////////////////////
//
// Map
//

CGM.Map = CGM.defClass({
    initialize: function (opt) {
	this._pos = this._$(opt.map_id);
	this._latlng = new google.maps.LatLng(opt.lat, opt.lng);
	this._spec = { zoom: opt.zoom
		     , center: this._latlng
	             , mapTypeId: opt.mapTypeId
                     };
	this._map = null;
    },
    display: function () {
	this._map = new google.maps.Map(this._pos, this._spec);
    },
    getMap: function () {
	return this._map;
    }
});

////////////////////////////////////////////////////////////////
//
// Gyms
//

CGM.Gyms = CGM.defClass({
    initialize: function (db, map) {
	this._db = db;
	this._map = map.getMap();
	this._markers = [];
	this._list = [];
	this._geocoder = new google.maps.Geocoder();
    },
    display: function () {
	var db = this._db;
	for (var i = 0; i < db.length; i++) {
	    this._newGym(db[i], this._map, i, this._markers);
	    this._list[i] = db[i].pref + ' ' + db[i].name;
	}
    },
    list: function () {
	return this._list;
    },
    // closure
    _newGym: function (ent, map, i, markers) {
	this._geocoder.geocode({'address': ent.addr}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
		var latlng = results[0].geometry.location;
		var marker = new google.maps.Marker({ position: latlng
	                                            , map: map
	                                            , title: ent.name
                                                    });
		markers[i] = marker; // using closure
		var infowindow = new google.maps.InfoWindow({ content: ent.html });
		google.maps.event.addListener(marker, 'click', function () {
		    infowindow.open(map, marker);
		});
	    }
	});
    },
    choose: function (gyms, i) {
	google.maps.event.trigger(gyms._markers[i], 'click'); // rule
    }
});

////////////////////////////////////////////////////////////////
//
// Menu
//

CGM.Menu = CGM.defClass({
    initialize: function (opt, gyms) {
	this._elm = this._$(opt.menu_id);
	this._gyms = gyms;
	this._form = this._$C('form');
	this._select = this._$C('select');
	this._form.appendChild(this._select);
	this._addOption('Select gym:');
	this._setHandler(this._select, 'change', this._choose(this._gyms));
    },
    _addOption: function (text) {
	var option = this._$C('option');
	option.appendChild(this._$T(text));
	this._select.appendChild(option);
    },
    display: function () {
	var list = this._gyms.list();
	for (var i = 0; i < list.length; i++) {
            this._addOption(list[i]);
	}
	this._elm.appendChild(this._form);
    },
    // closure
    _choose: function (gyms) {
	if (window.event) {
	    return function () {
		gyms.choose(gyms, window.event.srcElement.selectedIndex - 1);
	    };
	} else {
	    return function () {
		gyms.choose(gyms, this.selectedIndex - 1); // rule
	    };
	}
    }
});

