// Lingo callback function to display the current iteration count
        public static int MyCallback(int pLingoEnv, int nReserved, IntPtr pMyData)
        {
            var cb = new CallbackData();
            Marshal.PtrToStructure(pMyData, cb);

            int nIterations = -1;
            int nErr = lingo.LSgetCallbackInfoLng(pLingoEnv, lingo.LS_IINFO_ITERATIONS_LNG, ref nIterations);

            if (nErr == lingo.LSERR_NO_ERROR_LNG && nIterations != cb.nIterations)
                cb.nIterations = nIterations;

            Marshal.StructureToPtr(cb, pMyData, true);

            return 0;
        }
        public void MinimizeCost(IEnumerable<TransportUnit> transportUnits, int maxNumberOfSolutions)
        {
            int nPointersNow = -1;
            double dStatus = -1;
            double maxTripTime = double.MaxValue;

            foreach (TransportUnit unit in transportUnits)
            {
                unit.ProposedRoutes.Clear();
            }

            int solutionIndex;

            for (solutionIndex = 0; solutionIndex < maxNumberOfSolutions; solutionIndex++)
            {
                try
                {
                    System.Threading.Monitor.Enter(this);

                    // Open LINGO's log file

                    var logFile = Path.Combine(_logFileFolder.FullName, string.Format("lingo.{0}.log", Guid.NewGuid()));

                    int errorCode = lingo.LSopenLogFileLng(_pLingoEnv, logFile);
                    CheckIfError(errorCode);

                    // Let Lingo know we have a callback function
                    var cbd = new CallbackData();
                    var cb = new lingo.typCallback(LngCallback.MyCallback);

                    errorCode = lingo.LSsetCallbackSolverLng(_pLingoEnv, cb, cbd);
                    CheckIfError(errorCode);

                    // must pin lingo's transfer areas in memory
                    unsafe
                    {
                        fixed (double* pResult = new double[_numLegs],
                                      pMinTrp = _minTrp,
                                      pMaxTrp = _maxTrp,
                                      pCost = _cost,
                                      pDuration = _duration,
                                      pStartTime = _startTime,
                                      pRequestedVolume = new double[transportUnits.Count()],
                                      pTotalTripTime = new double[transportUnits.Count()],
                                      pMinStartTime = new double[transportUnits.Count()]
                               )
                        {
                            //clean mem.areas from previous runs
                            errorCode = lingo.LSclearPointersLng(_pLingoEnv);
                            CheckIfError(errorCode);

                            var inputFilePath = Path.Combine(_inputFileFolder.FullName, "logistikcenter.txt");

                            using (var inputFile = new StreamWriter(inputFilePath, false))
                            {
                                string demandString = string.Empty;

                                //nodes: TODO
                                inputFile.WriteLine("{0} ~", _nodeString);

                                //leg_id:n
                                inputFile.WriteLine("{0} ~", _legIdString);

                                //com type: TODO
                                inputFile.WriteLine("1 2 ~");

                                //transport
                                inputFile.WriteLine("{0} ~", _transportString);

                                //com cust sup
                                int currentUnit = 0;

                                foreach (TransportUnit transportUnit in transportUnits)
                                {
                                    demandString += (string.Format("1 {0} {1}\r\n", transportUnit.Origin.Id, transportUnit.Destination.Id));
                                    pRequestedVolume[currentUnit] = transportUnit.Cargo.Volume;

                                    TimeSpan span = (transportUnit.MaxDeliveryTime - _zeroTime);
                                    pTotalTripTime[currentUnit] = span.TotalHours;

                                    span = (transportUnit.MinPickupTime - _zeroTime);
                                    pMinStartTime[currentUnit] = span.TotalHours;

                                    currentUnit++;
                                }

                                //demand
                                inputFile.WriteLine("{0} ~", demandString);
                            }

                            // Pointer to the min totalCapacity
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pMinTrp[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the max totalCapacity
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pMaxTrp[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the cost
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pCost[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the duration
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pDuration[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the starttime
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pStartTime[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the customer demanded volume
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pRequestedVolume[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the customer demanded max time
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pTotalTripTime[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the customer demanded max time
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &pMinStartTime[0], ref nPointersNow);
                            CheckIfError(errorCode);

                            // max trip time
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &maxTripTime, ref nPointersNow);
                            CheckIfError(errorCode);

                            // Pointer to the solution status code
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &dStatus, ref nPointersNow);
                            CheckIfError(errorCode);

                            // Total trip time
                            double totalTripTime = -1;
                            errorCode = lingo.LSsetPointerLng(_pLingoEnv, &totalTripTime, ref nPointersNow);
                            CheckIfError(errorCode);

                            // Here is the script we want LINGO to run.
                            string cScript = string.Format("set echoin 1 \n take {0} \n go \n quit \n", _modelPath.FullName);

                            // Run the script
                            errorCode = lingo.LSexecuteScriptLng(_pLingoEnv, cScript);
                            CheckIfError(errorCode);

                            // Close the log file
                            lingo.LScloseLogFileLng(_pLingoEnv);

                            // Any problems?
                            if (errorCode != 0)
                                throw new FaildToSolveOptimizationException();

                            //hittade vi en lösning?
                            if (dStatus == lingo.LS_STATUS_GLOBAL_LNG || dStatus == lingo.LS_STATUS_LOCAL_LNG)
                            {
                                //get results
                                FetchResults(transportUnits);

                                //set max trip time to force another solution
                                maxTripTime = totalTripTime;
                            }
                        }

                    }
                }
                finally
                {
                    System.Threading.Monitor.Exit(this);
                }
            }
        }