bool P4StatusCommand::Run(P4Task& task, const CommandArgs& args)
{
	// Since the status command is use to check for online state we start out by
	// forcing online state to true and check if it has been set to false in the
	// end to determine if we should send online notifications.
	bool wasOnline = P4Task::IsOnline();
	P4Task::SetOnline(true);
	
	ClearStatus();

	bool recursive = args.size() > 1;
	Pipe().Log().Info() << "StatusCommand::Run()" << unityplugin::Endl;
			
	VersionedAssetList assetList;
	Pipe() >> assetList;
	
	RunAndSend(task, assetList, recursive);
	Pipe() << GetStatus();

	if (P4Task::IsOnline() && !wasOnline)
	{
		// If set to online already we cannot notify as online so we fake an offline state.
		P4Task::SetOnline(false);
		P4Task::NotifyOnline();
	}

	Pipe().EndResponse();

	return true;
}
	virtual bool Run(P4Task& task, const CommandArgs& args)
	{
		if (!task.IsConnected()) // Cannot login without being connected
		{
			Conn().Log().Info() << "Cannot login when not connected" << Endl;
			return false;
		}
		
		ClearStatus();
		
		m_LoggedIn = false;
		m_Password = task.GetP4Password();
		m_CheckingForLoggedIn = args.size() > 1;
		const string cmd = string("login") + (m_CheckingForLoggedIn ? string(" " ) + args[1] : string());

		if (!task.CommandRun(cmd, this) && !m_CheckingForLoggedIn)
		{
			string errorMessage = GetStatusMessage();			
			Conn().Log().Notice() << "ERROR: " << errorMessage << Endl;
		}
		
		if (m_CheckingForLoggedIn)
			Conn().Log().Debug() << "Is logged in: " << (m_LoggedIn ? "yes" : "no") << Endl;
		else
			Conn().Log().Info() << "Login " << (m_LoggedIn ? "succeeded" : "failed") << Endl;

		m_CheckingForLoggedIn = false;
		return m_LoggedIn;
	}
	virtual bool Run(P4Task& task, const CommandArgs& args)
	{
		//ConfigRequest req(args, task.
		if (args.size() < 2)
		{
			string msg = "Perforce plugin got invalid config setting :"; 
			for (CommandArgs::const_iterator i = args.begin(); i != args.end(); ++i) {
				msg += " ";
				msg += *i;
			}
			Conn().WarnLine(msg, MAConfig);
			Conn().EndResponse();
			return true;
		}
		
		string key = args[1];
		string value = Join(args.begin() + 2, args.end(), " ");
		
		ClearStatus();
		
		string logValue = value;
		if (key == "vcPerforcePassword")
			logValue = "*";

		Conn().Log().Info() << "Got config " << key << " = '" << logValue << "'" << Endl;

		// This command actually handles several commands all 
		// concerning connecting to the perforce server
		if (key == "vcPerforceUsername") 
		{
			task.SetP4User(value);
		}
		else if (key == "vcPerforceWorkspace")
		{
			task.SetP4Client(value);
		}
		else if (key == "projectPath")
		{
			task.SetProjectPath(TrimEnd(value));
			Conn().Log().Info() << "Set projectPath to" << value << Endl;
		}
		else if (key == "vcSharedLogLevel")
		{
			Conn().Log().Info() << "Set log level to " << value << Endl;
			LogLevel level = LOG_DEBUG;
			if (value == "info")
				level = LOG_INFO;
			else if (value == "notice")
				level = LOG_NOTICE;
			else if (value == "fatal")
				level = LOG_FATAL;
		    Conn().Log().SetLogLevel(level);
		}
		else if (key == "vcPerforcePassword")
		{
			task.SetP4Password(value);
			value = "*";
		}
		else if (key == "vcPerforceServer")
		{
			if (value.empty())
				value = "perforce";
			
			string::size_type i = (StartsWith(value, "ssl:") ? value.substr(4) : value).find(":");
			if (i == string::npos)
				value += ":1666"; // default port
			task.SetP4Port(value);
		}
		else if (key == "vcPerforceHost")
		{
			task.SetP4Host(value);
		}
		else if (key == "pluginVersions")
		{
			int sel = SelectVersion(args);
			Conn().DataLine(sel, MAConfig); 
			Conn().Log().Info() << "Selected plugin protocol version " << sel << Endl;
		}
		else if (key == "pluginTraits")
		{
			// We have 4 flags set
			Conn().DataLine("6");
			Conn().DataLine("requiresNetwork", MAConfig); 			
			Conn().DataLine("enablesCheckout", MAConfig);
			Conn().DataLine("enablesLocking", MAConfig);
			Conn().DataLine("enablesRevertUnchanged", MAConfig);
			Conn().DataLine("enablesChangelists", MAConfig);
			Conn().DataLine("enablesGetLatestOnChangeSetSubset", MAConfig);

			// We provide 4 configuration fields for the GUI to display
			Conn().DataLine("5");
			Conn().DataLine("vcPerforceUsername");               // key
			Conn().DataLine("Username", MAConfig);               // label
			Conn().DataLine("The perforce user name", MAConfig); // description
			Conn().DataLine("");                                 // default
			Conn().DataLine("1");                                // 1 == required field, 2 == password field

			Conn().DataLine("vcPerforcePassword");
			Conn().DataLine("Password", MAConfig);
			Conn().DataLine("The perforce password", MAConfig);
			Conn().DataLine("");
			Conn().DataLine("2"); // password field

			Conn().DataLine("vcPerforceWorkspace");
			Conn().DataLine("Workspace", MAConfig);
			Conn().DataLine("The perforce workspace/client", MAConfig);
			Conn().DataLine("");
			Conn().DataLine("1"); // required field

			Conn().DataLine("vcPerforceServer");
			Conn().DataLine("Server", MAConfig);
			Conn().DataLine("The perforce server using format: hostname:port. Port hostname defaults to 'perforce' and port defaults to 1666", MAConfig);
			Conn().DataLine("perforce");
			Conn().DataLine("0"); // 

			Conn().DataLine("vcPerforceHost");
			Conn().DataLine("Host", MAConfig);
			Conn().DataLine("The perforce host ie. P4HOST. It can often be left blank.", MAConfig);
			Conn().DataLine("");
			Conn().DataLine("0"); // 

			// We have 11 custom overlay icons
			Conn().DataLine("overlays");
			Conn().DataLine("11");
			Conn().DataLine(IntToString(kLocal)); // for this state
			Conn().DataLine("default");           // use this path. "default" and "blank" paths can be used when you have not custom overlays.
			Conn().DataLine(IntToString(kOutOfSync));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kCheckedOutLocal));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kCheckedOutRemote));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kDeletedLocal));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kDeletedRemote));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kAddedLocal));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kAddedRemote));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kConflicted));
			Conn().DataLine("default");
			Conn().DataLine(IntToString(kLockedLocal));
			Conn().DataLine("default");
		    Conn().DataLine(IntToString(kLockedRemote));
			Conn().DataLine("default");
		}
		else if (key == "end")
		{
			task.Logout();
			task.Disconnect();
			task.DisableUTF8Mode();
		}
		else 
		{
			Conn().WarnLine(ToString("Unknown config field set on version control plugin: ", key), MAConfig);
		}
		Conn().EndResponse();
		return true;
	}
    virtual bool Run(P4Task& task, const CommandArgs& args)
    {
        ClearStatus();
        Conn().Log().Info() << args[0] << "::Run()" << Endl;
        
        bool noLocalFileMove = args.size() > 1 && args[1] == "noLocalFileMove";

        VersionedAssetList assetList;
        Conn() >> assetList;
        
        if ( assetList.empty() ) 
        {
            Conn().EndResponse();
            return true;
        }
        
        // Process two assets at a time ie. src,dest
        if ( assetList.size() % 2 ) 
        {
            Conn().WarnLine("uneven number of assets during move", MASystem);
            Conn().EndResponse();
            return true;
        }

        VersionedAssetList::const_iterator b = assetList.begin();
        VersionedAssetList::const_iterator e = b;
        
        // Split into two steps. 1st make everything editable and 2nd do the move.
        // this makes changes more atomic.
        while (b != assetList.end())
        {
            e += 2;
            const VersionedAsset& src = *b;
            
            string paths = ResolvePaths(b, e, kPathWild | kPathRecursive);
            
            Conn().Log().Debug() << "Ensure editable source " << paths << Endl;
            
            string err;
            bool editable = (src.GetState() & (kCheckedOutLocal | kAddedLocal | kLockedLocal)) != 0;
            
            if (!editable)
            {
                string srcPath = ResolvePaths(b, b+1, kPathWild | kPathRecursive);
                Conn().Log().Info() << "edit " << srcPath << Endl;
                if (!task.CommandRun("edit " + srcPath, this))
                {
                    break;
                }
            }
            b = e;
        }

        b = assetList.begin();
        e = b;

        VersionedAssetList targetAssetList;
        string noLocalFileMoveFlag = noLocalFileMove ? " -k " : "";
        while (!HasErrors() && b != assetList.end())
        {
            e += 2;
            
            const VersionedAsset& src = *b;
            const VersionedAsset& dest = *(b+1);

            targetAssetList.push_back(dest);
            
            string paths = ResolvePaths(b, e, kPathWild | kPathRecursive);
            
            Conn().Log().Info() << "move " << noLocalFileMoveFlag << paths << Endl;
            if (!task.CommandRun("move " + noLocalFileMoveFlag + paths, this))
            {
                break;
            }
            
            // Make the actual file system move if perforce didn't do it ie. in
            // the case of an empty folder rename or a non versioned asset/folder move/rename
            if (!PathExists(dest.GetPath()))
            {
                // Move the file
                if (!MoveAFile(src.GetPath(), dest.GetPath()))
                {
                    string errorMessage = "Error moving file ";
                    errorMessage += src.GetPath();
                    errorMessage += " to ";
                    errorMessage += dest.GetPath();
                    Conn().WarnLine(errorMessage);
                }
            }

            // Delete move folder src since perforce leaves around empty folders.
            // This only works because unity will not send embedded moves.
            if (src.IsFolder() && IsDirectory(src.GetPath()))
            {
                DeleteRecursive(src.GetPath());
            }

            b = e;
        }
        
        // We just wrap up the communication here.
        Conn() << GetStatus();
        
        RunAndSendStatus(task, targetAssetList);
        
        Conn().EndResponse();

        return true;
    }