func main() {

	flag.Parse()
	if flag.NArg() < 2 {
		log.Fatal("Insufficient arguments to client")
	}

	cmd := flag.Arg(0)

	serverPort := fmt.Sprintf(":%d", *portnum)
	client := userclient.NewUserClient(serverPort, "localhost:"+strconv.Itoa(*portnum), *homedir)

	cmdlist := []cmd_info{
		{"uc", "UserClient.CreateUser", 3},
		{"au", "UserClient.AuthenticateUser", 2},
		{"s", "UserClient.Sync", 2},
		{"ts", "UserClient.ToggleSync", 2},
		{"ep", "UserClient.EditPermissions", 3},
	}

	cmdmap := make(map[string]cmd_info)
	for _, j := range cmdlist {
		cmdmap[j.cmdline] = j
	}

	ci, found := cmdmap[cmd]
	if !found {
		log.Fatal("Unknown command ", cmd)
	}
	if flag.NArg() < (ci.nargs + 1) {
		log.Fatal("Insufficient arguments for ", cmd)
	}

	switch cmd {
	case "uc": // user create
		// oh, Go.  If only you let me do this right...
		reply := &userproto.CreateUserReply{}
		err := client.CreateUser(&userproto.CreateUserArgs{flag.Arg(1), flag.Arg(2), flag.Arg(3)}, reply)
		PrintStatus(ci.funcname, reply.Status, err)
	case "au": //user authenticate
		reply := &userproto.AuthenticateUserReply{}
		err := client.AuthenticateUser(&userproto.AuthenticateUserArgs{flag.Arg(1), flag.Arg(2)}, reply)
		if err != nil {
			log.Fatal("Authorization error. Invalid User.")
		}
		PrintStatus(ci.funcname, reply.Status, err)
	case "s": //sync
		//err := client.Sync(flag.Arg(1))
		//PrintStatus(ci.funcname, reply.Status, err)
	case "ts": //toggle sync
		reply := &userproto.ToggleSyncReply{}
		err := client.ToggleSync(&userproto.ToggleSyncArgs{flag.Arg(1)}, reply)
		PrintStatus(ci.funcname, reply.Status, err)
	case "ep": //edit permissions
		permission, convErr := strconv.Atoi(flag.Arg(2))
		if convErr != nil {
			log.Fatal("The second argument must be the permissions")
		}
		reply := &userproto.EditPermissionsReply{}
		users := []string{}
		for i := 3; i < len(flag.Args()); i++ {
			users = append(users, flag.Arg(i))
		}
		err := client.EditPermissions(&userproto.EditPermissionsArgs{flag.Arg(1), permission, users}, reply)
		PrintStatus(ci.funcname, reply.Status, err)
	}
}
func main() {
	flag.Parse()

	serverPort := fmt.Sprintf(":%d", *portnum)
	client := userclient.NewUserClient(serverPort, "localhost:"+strconv.Itoa(*portnum), *homedir)

	cmdlist := []cmd_info{
		{"uc", "UserClient.CreateUser", 3},
		{"au", "UserClient.AuthenticateUser", 2},
		{"s", "UserClient.Sync", 2},
		{"ts", "UserClient.ToggleSync", 1},
		{"ep", "UserClient.EditPermissions", 3},
		{"cc", "UserClient.MakeClass", 1},
	}

	cmdmap := make(map[string]cmd_info)
	for _, j := range cmdlist {
		cmdmap[j.cmdline] = j
	}

	for *persistent {
		var cmd []byte
		reader := bufio.NewReader(os.Stdin)
		cmd, _, scanErr := reader.ReadLine()
		if scanErr == nil {
			cmdarray := strings.Split(string(cmd), " ")

			ci, _ := cmdmap[cmdarray[0]]

			switch cmdarray[0] {
			case "uc": // user create
				if len(cmdarray) != 4 {
					fmt.Println("Insufficient arguments to User Create.\nCorrect usage: uc <username> <password> <email address>\n")
					break
				}
				logged := client.IsLoggedIn()
				if logged != "" {
					fmt.Printf("You're already logged in as %v !", logged)
					break
				}
				// oh, Go.  If only you let me do this right...
				reply := &userproto.CreateUserReply{}
				err := client.CreateUser(&userproto.CreateUserArgs{cmdarray[1], cmdarray[2], cmdarray[3]}, reply)
				PrintStatus(ci.funcname, reply.Status, err)
			case "au": //user authenticate
				if len(cmdarray) != 3 {
					fmt.Println("Insufficient arguments to Authenticate User.\nCorrect usage: au <username> <password>\n")
					break
				}
				logged := client.IsLoggedIn()
				if logged != "" {
					fmt.Printf("You're already logged in as %v !", logged)
					break
				}
				reply := &userproto.AuthenticateUserReply{}
				err := client.AuthenticateUser(&userproto.AuthenticateUserArgs{cmdarray[1], cmdarray[2]}, reply)
				if err != nil {
					log.Fatal("Authorization error. Invalid User.")
				}
				PrintStatus(ci.funcname, reply.Status, err)
			case "s": //sync
				//err := client.Sync(flag.Arg(1))
				//PrintStatus(ci.funcname, reply.Status, err)
			case "cc": //make class / class create
				if len(cmdarray) != 2 {
					fmt.Println("Insufficient arguments to Class Create.\n")
					break
				}
				logged := client.IsLoggedIn()
				if logged == "" {
					fmt.Println("You're not logged in! Please login.")
					break
				}
				reply := &userproto.MakeClassReply{}
				err := client.MakeClass(&userproto.MakeClassArgs{cmdarray[1]}, reply)
				PrintStatus(ci.funcname, reply.Status, err)
			case "ts": //toggle sync
				if len(cmdarray) != 2 {
					fmt.Println("Insufficient arguments to Toggle Sync.\nCorrect usage: ts <filename>")
					break
				}
				logged := client.IsLoggedIn()
				if logged == "" {
					fmt.Println("You're not logged in! Please login.")
					break
				}
				reply := &userproto.ToggleSyncReply{}
				err := client.ToggleSync(&userproto.ToggleSyncArgs{cmdarray[1]}, reply)
				PrintStatus(ci.funcname, reply.Status, err)
			case "ep": //edit permissions
				if len(cmdarray) > 3 {
					fmt.Println("Insufficient arguments to Edit Permissions.\nCorrect usage: ep <file> <permissions to be set> <user1> <user2> ...")
					break
				}
				logged := client.IsLoggedIn()
				if logged == "" {
					fmt.Println("You're not logged in! Please login.")
					break
				}
				permission, convErr := strconv.Atoi(cmdarray[2])
				if convErr != nil {
					log.Fatal("The second argument must be the permissions")
				}
				reply := &userproto.EditPermissionsReply{}
				users := []string{}
				for i := 4; i < len(cmdarray); i++ {
					users = append(users, cmdarray[i])
				}
				err := client.EditPermissions(&userproto.EditPermissionsArgs{cmdarray[1], permission, users}, reply)
				PrintStatus(ci.funcname, reply.Status, err)
			default:
				fmt.Println("Not a valid command.")
			}
		}

	}
}