void NETBuildSystem::HandleToolUpdate(StringHash eventType, VariantMap& eventData)
    {
        if (curBuild_.Null() && !builds_.Size())
            return;

        if (curBuild_.Null())
        {
            // kick off a new build

            curBuild_ = builds_.Front();
            builds_.PopFront();


            FileSystem* fileSystem = GetSubsystem<FileSystem>();

            // Ensure solution still exists
            if (!fileSystem->FileExists(curBuild_->solutionPath_))
            {
                CurrentBuildError(ToString("Solution does not exist(%s)", curBuild_->solutionPath_.CString()));
                return;
            }

            String solutionPath = curBuild_->solutionPath_;

            String ext = GetExtension(solutionPath);

            bool requiresNuGet = true;

            if (ext == ".sln")
            {
                // TODO: handle projects that require nuget
                requiresNuGet = false;

                if (!fileSystem->FileExists(solutionPath))
                {
                    CurrentBuildError(ToString("Generated solution does not exist (%s : %s)", curBuild_->solutionPath_.CString(), solutionPath.CString()));
                    return;
                }

            }
            else if (ext == ".json")
            {
                SharedPtr<NETProjectGen> gen(new NETProjectGen(context_));

                gen->SetSupportedPlatforms(curBuild_->platforms_);
                gen->SetRewriteSolution(true);

                if (!gen->LoadJSONProject(solutionPath))
                {
                    CurrentBuildError(ToString("Error loading project (%s)", solutionPath.CString()));
                    return;
                }

                if (!gen->Generate())
                {
                    CurrentBuildError(ToString("Error generating project (%s)", solutionPath.CString()));
                    return;
                }

                solutionPath = gen->GetSolution()->GetOutputFilename();
                requiresNuGet = gen->GetRequiresNuGet();

                if (!fileSystem->FileExists(solutionPath))
                {
                    CurrentBuildError(ToString("Generated solution does not exist (%s : %s)", curBuild_->solutionPath_.CString(), solutionPath.CString()));
                    return;
                }

            }

            ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
            const String& nugetBinary = tenv->GetAtomicNETNuGetBinary();

            if (requiresNuGet && !fileSystem->FileExists(nugetBinary))
            {
                CurrentBuildError(ToString("NuGet binary is missing (%s)", nugetBinary.CString()));
                return;
            }

            StringVector stringVector;
            String platforms;
            StringVector processedPlatforms;
            String configs;

            for (unsigned i = 0; i < curBuild_->configurations_.Size(); i++)
            {
                stringVector.Push(ToString("/p:Configuration=%s", curBuild_->configurations_[i].CString()));
            }

            configs = String::Joined(stringVector, " ");
            stringVector.Clear();

            for (unsigned i = 0; i < curBuild_->platforms_.Size(); i++)
            {
                // map platform
                String platform = curBuild_->platforms_[i];

                if (platform == "windows" || platform == "macosx" || platform == "linux")
                {
                    ATOMIC_LOGINFOF("Platform \"%s\" mapped to \"desktop\"", platform.CString());
                    platform = "desktop";
                }

                if (processedPlatforms.Contains(platform))
                {
                    ATOMIC_LOGWARNINGF("Platform \"%s\" is duplicated, skipping", platform.CString());
                    continue;
                }

                processedPlatforms.Push(platform);

                if (platform == "desktop" || platform == "android")
                {
                    platform = "\"Any CPU\"";
                }
                else if (platform == "ios")
                {

                    platform = "\"Any CPU\"";
                    // TODO
                    // platform = "iPhone";
                }
                else
                {
                    ATOMIC_LOGERRORF("Unknown platform: %s, skipping", platform.CString());
                    continue;
                }

                platform = ToString("/p:Platform=%s", platform.CString());

                if (stringVector.Contains(platform))
                {
                    // This can happen when specifying Desktop + Android for example
                    continue;
                }

                stringVector.Push(platform);
            }

            platforms = String::Joined(stringVector, " ");
            stringVector.Clear();

            Vector<String> args;

#ifdef ATOMIC_PLATFORM_WINDOWS

            String cmdToolsPath = Poco::Environment::get("VS140COMNTOOLS", "").c_str();

            if (!cmdToolsPath.Length())
            {
                CurrentBuildError("VS140COMNTOOLS environment variable not found, cannot proceed");
                return;
            }

            if (!cmdToolsPath.EndsWith("\\"))
            {
                cmdToolsPath += "\\";
            }

            String msbuildcmd = ToString("%sVsMSBuildCmd.bat", cmdToolsPath.CString());

            String cmd = "cmd";

            args.Push("/A");
            args.Push("/C");

            // vcvars bat
            String compile = ToString("\"\"%s\" ", msbuildcmd.CString());

            if (requiresNuGet)
            {
                compile += ToString("&& \"%s\" restore \"%s\" ", nugetBinary.CString(), solutionPath.CString());
            }

            compile += ToString("&& msbuild \"%s\" %s %s", solutionPath.CString(), platforms.CString(), configs.CString());

            if (curBuild_->targets_.Size()) {

                StringVector targets;

                for (unsigned i = 0; i < curBuild_->targets_.Size(); i++)
                {
                    const char* tname = curBuild_->targets_[i].CString();
                    targets.Push(ToString("/t:\"%s:Rebuild\"", tname));
                }

                compile += " " + String::Joined(targets, " ");

            }

            // close out quote
            compile += "\"";

            args.Push(compile);

#else

            String compile;

            String cmd = "bash";
            args.Push("-c");

            String xbuildBinary = tenv->GetMonoExecutableDir() + "xbuild";

            if (requiresNuGet)
            {
#ifdef ATOMIC_PLATFORM_OSX
                compile += ToString("\"%s\" restore \"%s\" && ", nugetBinary.CString(), solutionPath.CString());
#else
                compile += ToString("mono \"%s\" restore \"%s\" && ", nugetBinary.CString(), solutionPath.CString());
#endif
            }

            compile += ToString("\"%s\" \"%s\" %s %s", xbuildBinary.CString(), solutionPath.CString(), platforms.CString(), configs.CString());

            if (curBuild_->targets_.Size()) {

                StringVector targets;

                for (unsigned i = 0; i < curBuild_->targets_.Size(); i++)
                {
                    const char* tname = curBuild_->targets_[i].CString();
                    targets.Push(ToString("%s:Rebuild", tname));
                }

                compile += " /target:\"" + String::Joined(targets, ";") + "\"";

            }

            args.Push(compile);

#endif

            curBuild_->allArgs_.Join(args, " ");

            SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
            Subprocess* subprocess = nullptr;

            ATOMIC_LOGINFOF("%s : %s", cmd.CString(), curBuild_->allArgs_.CString());

            try
            {
                subprocess = subs->Launch(cmd, args, "");
            }
            catch (Poco::SystemException)
            {
                subprocess = nullptr;
            }

            if (!subprocess)
            {
                CurrentBuildError(ToString("NETCompile::Compile - Unable to launch MSBuild subprocess\n%s", curBuild_->allArgs_.CString()));
                return;
            }

            VariantMap buildBeginEventData;
            buildBeginEventData[NETBuildBegin::P_BUILD] = curBuild_;
            SendEvent(E_NETBUILDBEGIN, buildBeginEventData);

            SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, ATOMIC_HANDLER(NETBuildSystem, HandleCompileProcessComplete));
            SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, ATOMIC_HANDLER(NETBuildSystem, HandleSubprocessOutput));

            curBuild_->status_ = NETBUILD_BUILDING;

        }

    }