function calView(container) {

    //The necessary vars for a View...
    this.name="Calendar";        //Display name of this view.
    var queryStates = [];
    this.queryStates=queryStates;          //All Queries currently in this view.
    this.container=container; //HTML DOM parent node for this view.
    //this.container.setAttribute('ondblclick','CalendarDoubleClick(event)')
    //the above line is redundant, since bigCal.js already has it.

    // vars for calView
    var calendar = new VIEWAS_bigCal(this.container, new Date());
    
    // allEvents is an map/associative array<q.id, events>. all drawn events
    var allEvents = [];

    //helper functions--------------------------------------------//
    //functions for adding and removing events from EC and allEvents
    function dayEventDup(e, dayevents){
	for (i = 0; i<dayevents.length; i++){
	    var e2 = dayevents[i];
	    if (e2.id == e.id){
		return true;
	    }
	}
	return false;
    }
    
    function dateArray2Date(dateArray){
	var date = new Date();
	date.setTime(0);
	date.setFullYear(dateArray[0], dateArray[1], dateArray[2]);
	return date;
    }
    
    // drawfn is a function that takes in 4 arguments My, Mm, Md, and an event e
    // used in drawQuery and undrawQuery
    function eventDurForeach(e, drawfn){
	var msPerDay = 86400000;
	var Adate = dateArray2Date(e.startArray);
	var Bdate = dateArray2Date(e.endArray);
	
	var Atime = Adate.getTime();
	var Btime = Bdate.getTime();
	for (var k = Atime; k <= Btime; k+=msPerDay){
	    var middleDate = new Date();
	    middleDate.setTime(k);
	    var My = middleDate.getFullYear();
	    var Mm = middleDate.getMonth();
	    var Md = middleDate.getDate();
	    
	    // add to total events if not duplicate
	    drawfn(My, Mm, Md, e);
	}
    }    
    //end helper functions----------------------------------------//

    this.drawQuery = function (q) {
        this.queryStates[q.id]=1;
        this.onBinding = function (bindings) {
        
        // helper functions
            var currentDate = new Date();
            function parseY(str){return (str!=undefined) ? parseInt(str.substr(0,4), 10) : currentDate.getFullYear();}
            function parseM(str){return (str!=undefined) ? parseInt(str.substr(5,2), 10) : currentDate.getMonth();}
            function parseD(str){return (str!=undefined) ? parseInt(str.substr(8,2), 10) : currentDate.getDate();}
            function parseT(str){return (str!=undefined) ? str.slice(11) : 'time';}
            
            var Ay, Am, Ad, At;
            var By, Bm, Bd, Bt;
            var summary;
            
            // if everything needed is defined
            function allDefined(array){
                for (key in array){
                    if (array[key]==undefined){
                        return false;
                    }
                }
                return true;
            }

            function readSt(){
                // helper function            
		tinfo("making a calendar w/ bindings " + bindings);
		var nv = q.vars.length;    // number of variables/calendars
        
		function contains(str, array){
		    for (i = 0; i<array.length; i++){
			if (array[i]==str){
			    return true;
			}
		    }
		    return false;
		}
		function isFrag(calType){
		    var eventFrag = ['end','start','summary'];
		    return contains(calType,eventFrag);
		}
		
		function calDF(calType){
		    // helper function
		    function dateStr(dt){
			return  (dt.value!=undefined) ? dt.value : kb.the(dt, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#dateTime'), undefined);
		    }
		    
		    switch(calType){
			// disallow Vcalendar for now
			/*
			  case 'Vcalendar':
			  // settle Vcalendar children first, depth-first
			  // Vcal can have many components
			  return function(obj){
			  var comps = kb.each(obj, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#component'), undefined);
			  map(calDF('component'), comps);
			  }
			*/
			case 'component':
			// the only calendar components I know of are events.
			return function(obj){
			    // var event = kb.the(obj, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#Vevent'), undefined);
			    var event = obj;
			    calDF('event')(event);
			}
			case 'event':
			return function(obj){
			    var dtstart = kb.the(obj, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#dtstart'), undefined);
                            calDF('start')(dtstart);
			    // dtend might not be specified for event
                            // if I use kb.the, it will complain if no hits return.
			    
			    var dtend = kb.any(obj, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#dtend'), undefined);
			    if (dtend != undefined){
                                calDF('end')(dtend);
			    }
			    summary = kb.the(obj, kb.sym('http://www.w3.org/2002/12/cal/icaltzd#summary'), undefined).value;
			    return obj;
			}
			case 'start':
			return function(obj){
			    var datestrA = dateStr(obj);
			    // YYYY MM DD time string
			    Ay = parseY(datestrA);
			    Am = parseM(datestrA);
			    Ad = parseD(datestrA);
			    At = parseT(datestrA); // string
			    if (summary==undefined){
				summary = 'dtstart';
			    }
			}
			case 'end':
			return function(obj){
			    var datestrB = dateStr(obj);
			    By = parseY(datestrB);
			    Bm = parseM(datestrB);
			    Bd = parseD(datestrB);
			    Bt = parseT(datestrB); // string
			    if (summary==undefined){
				summary = 'dtend';
			    }
			}
			case 'summary':
			return function(obj){
			    summary = obj.value;
			}
			case 'dateThing':
			return function(obj){
			    var sublabel = label(sub);
			    summary = (sublabel!=undefined) ? sublabel : sub.toString();
			    calDF('start')(obj);
			}
			default:
			return function(obj){
			    // what to do with non-calendar information
			}
		    }
		    // for each query var, handle data
		}
		
		
		for (i=0; i<nv; i++) {
		    // find what calType object (or subject?) of statement is
                    // by looking at the predicate?
		    var qst = q.pat.statements[i];
		    var calType = findCalType(qst.predicate.toString());
		    var obj = (qst.object.isVar==1)? bindings[qst.object] : qst.object;
		    var sub = (qst.subject.isVar==1)? bindings[qst.subject] : qst.subject;
		    
		    // calDF binds variables needed to create an entry in calendar
		    /* if (calType){
		       calDF(calType)(obj);
		       return (calType=='dateThing') ? sub : obj;
		       }*/
		    if (calType!=null){
			/*if (isFrag(calType)){
			  calDF('event')(sub);
			  return sub;
			  } else {*/
			calDF(calType)(obj);
			// return (calType=='dateThing') ? sub : obj;
			if (calType=='dateThing'){
			    return sub;
			} else if (calType=='component' || calType=='event'){
			    return obj;
			}
			//}
		    }
		}
		return null;
            }
            
            var obj = readSt();
            summary = (summary!=undefined)? summary : "summary";
	    
	    if (!allDefined([By,Bm,Bd])){
		By = Ay;
		Bm = Am;
		Bd = Ad;
		Bt = At;
	    }
	    
	    if (!allDefined([Ay,Am,Ad])){
		Ay = By;
		Am = Bm;
		Ad = Bd;
		At = Bt;
	    }
	    
            if (allDefined([Ay, Am, Ad, At, summary])){
		// adds the event to days it spans in EC
		function drawfn(My, Mm, Md, e){
		    var dayevents = getSlot([My,Mm,Md], calendar.EC);
		    if (!dayEventDup(e,dayevents)){
			dayevents.push(e);
			getSlot([q.id], allEvents).push(e);
			dayevents.sort(sortByEventTime);
			// show number of events, if it is amongst currently shown queries
			if (queryStates[e.qid]==1){
			    calendar.showEventCount(My,Mm,Md);
			}
		    } //else {break;}
		}

                // create JS Event object                
                var e = new Event([Ay, Am, Ad], At, [By, Bm, Bd], Bt, summary, obj, q.id);
		eventDurForeach(e, drawfn);
	    }
	}
        
        kb.query(q, this.onBinding, myFetcher);
        // show number of events
        calendar.currentMonthEventCount();

        return this.container;
    } //this.drawQuery

    this.undrawQuery = function (q) {
        //Joyce, you're going to have to write this one.
        //It should undraw a query and then set its state to be 0 (undrawn).
        //I guess the main point here is, in order to do this on one calendar
        //you WILL NOT be able to use emptyNode(this.container);
        // emptyNode(this.container); //THIS IS NOT SUFFICIENT.
	//
	function undrawfn(My, Mm, Md, e){
	    var dayevents = getSlot([My,Mm,Md], calendar.EC);
	    /*for (var i in dayevents){
		var e2 = dayevents[i];
		delete dayevents[i];
		break;
		}*/
	    var newdayevents = filter(function(e2){return (e2.id!=e.id);}, dayevents);
	    getSlot([My, Mm], calendar.EC)[Md] = newdayevents;
	}

	var queryEvents = allEvents[q.id];
	for (var i in queryEvents){
	    var e = queryEvents[i];
	    eventDurForeach(e, undrawfn);
	}
	delete allEvents[q.id];
	calendar.currentMonthEventCount();
        this.queryStates[q.id]=0;
    }
    
    this.addQuery = function (q) {
	// adds all queries. if queries don't have any relevant calendar data,
	// the calendar will be blank.
        this.queryStates[q.id]=0;
    }

    this.removeQuery = function (q) {
        //Joyce, this one again is up to you.  I'm really striking out :(
        //Should delete a query altogether from the view.
        //If you write undrawQuery correctly, the below should be good enough.
        this.undrawQuery(q);
        delete this.queryStates[q.id];
    }

    this.clearView = function () {
        emptyNode(this.container);
        var i;
        for(i=0; i<this.queryStates.length; i++) {
            this.queryStates[i]=0;
        }
    }
} // calView
function findCalType (st) {
    var types = {'icaltzd#dtend':'end', 'icaltzd#dtstart':'start', 'icaltzd#summary':'summary', 'icaltzd#Vevent':'event', 'icaltzd#component':'component', 'date':'dateThing'};
    for (key in types){
	// match: finds substrings
	if(st.toLowerCase().match(key.toLowerCase())!=null){
	    return types[key];
	}
    }
    return null;
}

