/// <summary>
        /// Return the segment in a sequence of same seg Id as previous segment
        /// </summary>
        /// <param name="products"></param>
        /// <returns></returns>
        public override TrackSegment DeliverProduct(ref TrackSegment[] products, int maxSegLevel)
        {
            //Random seed
            Random.InitState((int)System.DateTime.Now.Ticks);

            //Check whether segments spawned in sequence have reached its limit
            if (segCount >= SEQUENTIAL_SEGMENT_COUNT)
            {
                //If yes then spawn new sequential segments
                segCount  = 0;
                prevSegID = Random.Range(0, 3);
            }


            //Get possible segments of same segId as previous segment and in range of max difficulty level
            TrackSegment segment = null;

            /*List<TrackSegment>*/
            possibleSegments = trackSegmentPool.FindAll(x => !x.gameObject.activeSelf &&
                                                        x.segID == prevSegID && x.segLevel <= maxSegLevel);

            //If there are any possible segments, then choose 1 from it
            if (possibleSegments.Count > 0)
            {
                int rand = Random.Range(0, possibleSegments.Count);
                segment = possibleSegments[rand];
            }

            //If there are 0 possible segments, then create one
            if (segment == null)
            {
                //Search the prefabs / segment types
                for (int i = 0; i < products.Length; i++)
                {
                    //If a prefab matches the segId to spawn and is in range of max difficulty level
                    if (products[i].segID == prevSegID && products[i].segLevel <= maxSegLevel)
                    {
                        //Instantiate it
                        segment = Object.Instantiate(products[i]);
                        break;
                    }
                }

                //Add in the pool
                trackSegmentPool.Add(segment);
            }

            //Increment segment counter
            prevSegID = segment.segID;
            segCount++;

            //Clear possible segment list to avoid garbage collection
            possibleSegments.Clear();

            return(segment);
        }
 /// <summary>
 /// Manufacture segments sequentially and evenly
 /// If there are 3 segment types and quantity is 21, then 7 segments of each type will be manufactured
 /// </summary>
 /// <param name="productQuantity"></param>
 /// <param name="products"></param>
 /// <param name="productParent"></param>
 public override void ManufactureProduct(int productQuantity, ref TrackSegment[] products, Transform productParent)
 {
     for (int j = 0; j < products.Length; j++)
     {
         for (int i = 0; i < productQuantity / products.Length; i++)
         {
             TrackSegment newSegment = (TrackSegment)Object.Instantiate(products[j]);
             newSegment.gameObject.SetActive(false);
             newSegment.transform.SetParent(productParent);
             trackSegmentPool.Add(newSegment);
         }
     }
 }
        /// <summary>
        /// Returns a randomly chosen track segment
        /// </summary>
        /// <param name="products"></param>
        /// <returns>A random track segment from the pool</returns>
        public override TrackSegment DeliverProduct(ref TrackSegment[] products, int maxSegLevel)
        {
            //Random seed
            Random.InitState((int)System.DateTime.Now.Ticks);

            TrackSegment segment = null;

            //Find all possible segments that can be returned in range of difficulty level
            possibleSegments = trackSegmentPool.FindAll(x => !x.gameObject.activeSelf && x.segLevel <= maxSegLevel);

            //If there are any possible segments
            if (possibleSegments.Count > 0)
            {
                //Choose randomly
                int rand = Random.Range(0, possibleSegments.Count);
                segment = possibleSegments[rand];
            }

            //Create new random segment, if 0 possible segments
            if (segment == null)
            {
                //Check if new segment fits within the possible difficulty level, then add it to possible spawns
                for (int i = 0; i < products.Length; i++)
                {
                    if (products[i].segLevel <= maxSegLevel)
                    {
                        possibleRandomSegments.Add(i);
                    }
                }

                //Create one random segment from possible spawns
                if (possibleRandomSegments.Count > 0)
                {
                    int rand = Random.Range(0, possibleRandomSegments.Count);
                    segment = Object.Instantiate(products[possibleRandomSegments[rand]]);

                    trackSegmentPool.Add(segment);
                }

                else
                {
                    Utils.DebugUtils.LogError("Please make sure track segments prefabs provided to create pool includes atleast 1 prefab of all difficulty levels");
                }
            }

            possibleSegments.Clear();
            possibleRandomSegments.Clear();

            //Return random segment
            return(segment);
        }
        /// <summary>
        /// Despawn the segment
        /// </summary>
        /// <param name="deSpawnIndex"></param>
        public void DeSpawnTrackSegment(int deSpawnIndex)
        {
            TrackSegment despawnSegment = activeSegments[deSpawnIndex];

            //Despawn obstacles
            ObstacleSpawner.DeSpawnObstacles(ref despawnSegment);

            //Deactivate segment
            despawnSegment.gameObject.SetActive(false);
            despawnSegment.transform.SetParent(this.transform);

            //Remove from active segments
            activeSegments.RemoveAt(deSpawnIndex);
        }
        /// <summary>
        /// Manufacture tracksegments randomly from the provided prefabs
        /// </summary>
        /// <param name="productQuantity">Amount to manufacture</param>
        /// <param name="products">Prefabs / types of tracksegments that can be manufactured</param>
        /// <param name="productParent">Transform under which to keep the pooled segments</param>
        public override void ManufactureProduct(int productQuantity, ref TrackSegment[] products, Transform productParent)
        {
            //Random seed
            Random.InitState((int)System.DateTime.Now.Ticks);

            //Segemnts to manufacture(pool)
            for (int i = 0; i < productQuantity; i++)
            {
                //Get random segment to pool
                TrackSegment newSegment = (TrackSegment)Object.Instantiate(products[Random.Range(0, products.Length)]);

                //Set parent, disable and add it to pool
                newSegment.gameObject.SetActive(false);
                newSegment.transform.SetParent(productParent);
                trackSegmentPool.Add(newSegment);
            }
        }
        /// <summary>
        /// Spawn track segment
        /// </summary>
        private void Spawn()
        {
            //Get a track segment from the factory's pool
            TrackSegment newSegment = segmentFactory.DeliverProduct(ref trackProducts, maxSegmentLevel);

            //If we have atleast 1 segment spawned
            if (activeSegments.Count > 0)
            {
                //Set value of current exit to the last spawned segment
                currentExitPoint = activeSegments[activeSegments.Count - 1].segmentExit.transform.position;
            }

            //Else we start from 0
            else
            {
                currentExitPoint = Vector3.zero + newSegment.segmentEntry.position;
            }

            //Entry point for new segment to be spawned
            entryPoint = newSegment.segmentEntry.transform.position;

            //Position of new segment will be last segment's exit position - new segment entry position
            pos = currentExitPoint + (newSegment.transform.position - entryPoint);
            newSegment.transform.position = pos;

            //Activate segment and set its parent
            newSegment.gameObject.SetActive(true);
            newSegment.transform.SetParent(trackSegmentRoot);

            //Update current Z distance
            currentZDistance = newSegment.segmentExit.transform.position.z;

            //Add to active segments pool
            activeSegments.Add(newSegment);

            //Spawn obstacles
            ObstacleSpawner.SpawnObstacles(ref newSegment);
        }