/* parse.c 718b */
XDef parse(Par p) {
    switch (p->alt) {
    case ATOM:
        /* parse ATOM and return 718c */
        return mkDef(mkExp(parseexp(p)));
    case LIST:
        /* parse LIST and return 718d */
        {
            Parlist pl = p->u.list;

            if (pl == NULL)
                error("%p: empty list", p);
            if (nthPL(pl, 0)->alt == ATOM) {
                Name first = nthPL(pl, 0)->u.atom;
                if (first == strtoname("define")) {
                    /* parse define and return 719a */
                    Name name;
                    Lambda l;

                    if (lengthPL(pl) != 4 || nthPL(pl, 1)->alt != ATOM || nthPL(
                                                            pl, 2)->alt != LIST)
                        error("%p: usage: (define fun (args) body)", p);

                    name      = nthPL(pl, 1)->u.atom;
                    l.formals = getnamelist(p, nthPL(pl, 2)->u.list);
                    l.body    = parseexp(nthPL(pl, 3));
                    return      mkDef(mkDefine(name, l));
                }
                if (first == strtoname("val")) {
                    /* parse val and return 719b */
                    Exp var, exp;

                    if (lengthPL(pl) != 3)
                        error("%p: usage: (val var exp)", p);

                    var = parseexp(nthPL(pl, 1));
                    if (var->alt != VAR)
                        error("%p: usage: (val var exp) (bad variable)", p);

                    exp = parseexp(nthPL(pl, 2));
                    return mkDef(mkVal(var->u.var, exp));
                }
                if (first == strtoname("use")) {
                    /* parse use and return 719c */
                    if (lengthPL(pl) != 2 || nthPL(pl, 1)->alt != ATOM)
                        error("%p: usage: (use filename)", p);

                    return mkUse(nthPL(pl, 1)->u.atom);
                }
                if (first == strtoname("check-expect")) {
                    /* parse check-expect and return 719d */
                    {
                    Exp check, expect;

                    if (lengthPL(pl) != 3)
                        error("%p: usage: (check-expect exp exp)", p);

                    check  = parseexp(nthPL(pl, 1));
                    expect = parseexp(nthPL(pl, 2));
                    return mkTest(mkCheckExpect(check, expect));
                    }
                }
                if (first == strtoname("check-error")) {
                    /* parse check-error and return 719e */
                    {
                    Exp check;

                    if (lengthPL(pl) != 2)
                        error("%p: usage: (check-error exp)", p);

                    check  = parseexp(nthPL(pl, 1));
                    return mkTest(mkCheckError(check));
                    }
                }
            }

            return mkDef(mkExp(parseexp(p)));
        }
    }
    assert(0);
    return NULL;
}
/*
 * The parser needs to take concrete syntax, check to
 * see that it is well formed, and produce abstract
 * syntax. It provides the [[readtop]] function.
 * 
 * At the top level, parsing amounts to looking for top
 * level constructs and passing the rest of the work to
 * [[parseexp]], which parses the input into [[Exp]]s.
 * <parse.c>=
 */
static XDef parse(Par p) {
    switch (p->alt) {
    case ATOM:
        /*
         * If we have a name, we treat it as an expression.
         * <parse [[atom]] and return the result>=
         */
        return mkDef(mkExp(parseexp(p)));
    case LIST:
        /*
         * If we have a list, we need to look for [[define]],
         * [[val]], and [[use]].
         * <parse [[list]] and return the result>=
         */
        {
            Name first;
            Parlist pl = p->u.list;
            if (pl == NULL)
                error("%p: empty list", p);
            if (nthPL(pl, 0)->alt != ATOM)
                error("%p: first item of list not name", p);

            first = nthPL(pl, 0)->u.atom;
            if (first == strtoname("define")) {
                /*
                 * Parsing definitions requires checking the argument
                 * counts and then parsing the subpieces. For function
                 * definitions, we could check that formal parameters
                 * have distinct names, but that check is part of the
                 * operational semantics for function definition.
                 * <parse [[define]] and return the result>=
                 */
                if (lengthPL(pl) != 4 || nthPL(pl, 1)->alt != ATOM || nthPL(pl,
                                                                2)->alt != LIST)
                    error("%p: usage: (define fun (formals) body)", p);

                {
                  Name     name    = nthPL(pl, 1)->u.atom;
                  Namelist formals = getnamelist(name, p, nthPL(pl, 2)->u.list);
                  Exp      body    = parseexp(nthPL(pl, 3));
                  return mkDef(mkDefine(name, mkUserfun(formals, body)));
                }
            }
            if (first == strtoname("val")) {
                /*
                 * <parse [[val]] and return the result>=
                 */
                Exp var, exp;

                if (lengthPL(pl) != 3)
                    error("%p: usage: (val var exp)", p);

                var = parseexp(nthPL(pl, 1));
                if (var->alt != VAR)
                    error("%p: usage: (val var exp) (bad variable)", p);

                exp = parseexp(nthPL(pl, 2));
                return mkDef(mkVal(var->u.var, exp));
            }
            if (first == strtoname("use")) {
                /*
                 * <parse [[use]] and return the result>=
                 */
                if (lengthPL(pl) != 2 || nthPL(pl, 1)->alt != ATOM)
                    error("%p: usage: (use filename)", p);

                return mkUse(nthPL(pl, 1)->u.atom);
            }
            if (first == strtoname("check-expect")) {
                /*
                 * <parse [[check-expect]] and return the result>=
                 */
                Exp check, expect;

                if (lengthPL(pl) != 3)
                    error("%p: usage: (check-expect exp exp)", p);

                check  = parseexp(nthPL(pl, 1));
                expect = parseexp(nthPL(pl, 2));
                return mkTest(mkCheckExpect(check, expect));
            }
            if (first == strtoname("check-error")) {
                /*
                 * <parse [[check-error]] and return the result>=
                 */
                Exp check;

                if (lengthPL(pl) != 2)
                    error("%p: usage: (check-error exp)", p);

                check  = parseexp(nthPL(pl, 1));
                return mkTest(mkCheckError(check));
            }
            return mkDef(mkExp(parseexp(p)));
        }
    }
    assert(0);
    return NULL;
}
int main(int argc, char *argv[]) {

	printf("Threaded Ticket Seller - Project  3\n");
	// Garbage seller is used to hold persons that
	//   have been processed by the other sellers
	//   we have to wait on possible frustrated users
	//   threads have cleared or they may crash when their
	//   data is freed
	garbage = createSeller(HIGH, 11);
	// finish creation of the concert hall
	hall.isSoldOut = FALSE;
	hall.hasStarted = FALSE;
	hall.lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
    pthread_mutex_init(hall.lock,NULL);
    pthread_mutex_init(&outputLock,NULL);

	if (argc == 2) {
		if (argv[1][0] == 'T') {
			// do self test
			printf("Self Test\n");
			mkTest();
			printf("Self test succeeded\n");
			exit(0);
		}
		int N = atoi(argv[1]);
		printf("Run with %d customers per ticket seller\n", N);

		//Create Sellers
		Seller *allSellers[NUM_SELLERS];

		allSellers[0] = createSeller(HIGH, 0);

		int i;
		for (i = 1; i < 4; i++) {
				allSellers[i] = createSeller(MEDIUM, i);
		}

		for(i = 1; i < 7; i++){
			allSellers[i+3] = createSeller(LOW, i + 3);
		}

		//declare person pointer
		Person *p;

		int sellerNum;
		
		//create thread when adding person to the Seller que
		pthread_t personThreadId[NUM_SELLERS*N];

		//create thread for putting people into concert hall
		pthread_t sellerThreadId[NUM_SELLERS];

		pthread_t timerTID;
		pthread_create(&timerTID,NULL,&timer,NULL);

		for (sellerNum = 0; sellerNum < NUM_SELLERS; sellerNum++)
		{
			pthread_create(&sellerThreadId[sellerNum], NULL,
				       &sellTickets, (void *) allSellers[sellerNum]);
			for(i = 0; i < N; i++)
			{
				p = createPerson(allSellers[sellerNum]);
				//p->arrival = 0;
				pthread_create(&personThreadId[sellerNum*N+i], NULL,
					       &addPerson, (void *) p);
			}
		}

		closeDoorsIn60Minutes();
		waitForSellersToFinish(allSellers,NUM_SELLERS);

	} else {
		printf("Usage:\n");
		printf("threadSeller [T|number]\n");
		printf(" T - run self test without any threading\n");
		printf(" number - number of customers per ticket seller\n");
		printf("             full threaded simulation\n");
	}

	printf("Exiting threadSeller\n");
	return 0;
}
/* parse.c 694a */
static XDef parse(Par p) {
    switch (p->alt) {
    case ATOM:
        /* parse [[atom]] and return the result 694b */
        return mkDef(mkExp(parseexp(p)));
    case LIST:
        /* parse [[list]] and return the result 694c */
        {
            Name first;
            Parlist pl = p->u.list;
            if (pl == NULL)
                error("%p: empty list", p);
            if (nthPL(pl, 0)->alt != ATOM)
                error("%p: first item of list not name", p);

            first = nthPL(pl, 0)->u.atom;
             if (first == strtoname("define")) {
                 /* parse [[define]] and return the result */
                 if (lengthPL(pl) != 5 || nthPL(pl, 1)->alt != ATOM || 
                     nthPL(pl, 2)->alt != LIST || nthPL(pl, 3)->alt != LIST)
                     error("%p: usage: (define fun (formals) (locals) body)", p);
               {
                 Name     name    = nthPL(pl, 1)->u.atom;
                 Namelist formals = getnamelist(name, p, nthPL(pl, 2)->u.list);
                 Namelist locals  = getnamelist(name, p, nthPL(pl, 3)->u.list);
                 Exp      body    = parseexp(nthPL(pl, 4));
                 return   mkDef(mkDefine(name, mkUserfun(formals, locals, body)));
               }
             }

            if (first == strtoname("val")) {
                /* parse [[val]] and return the result 695c */
                Exp var, exp;

                if (lengthPL(pl) != 3)
                    error("%p: usage: (val var exp)", p);

                var = parseexp(nthPL(pl, 1));
                if (var->alt != VAR)
                    error("%p: usage: (val var exp) (bad variable)", p);

                exp = parseexp(nthPL(pl, 2));
                return mkDef(mkVal(var->u.var, exp));
            }
            if (first == strtoname("use")) {
                /* parse [[use]] and return the result 695d */
                if (lengthPL(pl) != 2 || nthPL(pl, 1)->alt != ATOM)
                    error("%p: usage: (use filename)", p);

                return mkUse(nthPL(pl, 1)->u.atom);
            }
            if (first == strtoname("check-expect")) {
                /* parse [[check-expect]] and return the result 695e */
                Exp check, expect;

                if (lengthPL(pl) != 3)
                    error("%p: usage: (check-expect exp exp)", p);

                check  = parseexp(nthPL(pl, 1));
                expect = parseexp(nthPL(pl, 2));
                return mkTest(mkCheckExpect(check, expect));
            }
            if (first == strtoname("check-error")) {
                /* parse [[check-error]] and return the result 696a */
                Exp check;

                if (lengthPL(pl) != 2)
                    error("%p: usage: (check-error exp)", p);

                check  = parseexp(nthPL(pl, 1));
                return mkTest(mkCheckError(check));
            }
            return mkDef(mkExp(parseexp(p)));
        }
    }
    assert(0);
    return NULL;
}