--
-- handles spawning of road exits, and other things
--

TEST_EXIT_NODE = nil

function roadstream_ctor (self)

--   TEST_EXIT_NODE = node_town

   self.type = nil -- 1 == interstate, 2 == highway, 3 == road
   self.seed = nil
   self.name = "Nameless Road"

   -- the current terrain; 1 == desert, 2 == prairie, 3 == mountains
   self.terrain_type = 1

   -- these are set based on the type parameters
   self.num_cars = 0

   -- the current "event"; this is essentially a list of segments to return; when
   -- we run out, we generate some more into here; but we want to generate a bunch
   -- at a time, e.g., go straight for X seconds, etc.
   self.cur_event_type = nil -- 1 == straight, 2 == increase lanes, 3 == decrease lanes, 4 == passing lanes, 5 == exit
   self.cur_median = nil -- depends really on highway type
   self.cur_lanes = nil
   self.cur_rlanes = nil
   self.cur_segs = {}

end

roadstream = class (roadstream_ctor)

function roadstream:copy (Roadstream, Seed)

   self.type = Roadstream.type
   self.terrain_type = Roadstream.terrain_type
   self.seed = Seed
   self:set_lanes (Roadstream.cur_lanes, Roadstream.cur_rlanes, Roadstream.cur_median)
   self.name = Roadstream.name
   self.cur_event_type = 1
   self:add_event_segs (self.cur_event_type)

   RN_seed (Seed)
end

function roadstream:init (Type, TerrainType, Seed)

   self.type = Type
   self.terrain_type = TerrainType
   self.seed = Seed

   RN_seed (Seed)

   if (1 == self.type) then

      local R = RN ()
      if (R < 0.35) then self:set_lanes (4, 4, 2) -- busy interstate
      else self:set_lanes (3, 3, 2) -- medium busy
      end

      self.name = "Interstate " .. RN_index (50)

   elseif (2 == self.type) then

      if (RN () < 0.5) then self:set_lanes (3, 3, 0) -- not busy highway
      else self:set_lanes (2, 2, 0) -- not busy highway
      end

      self.name = table_choose { "Route", "Highway" }
      self.name = self.name .. " " .. RN_index (99)

   elseif (3 == self.type) then

      self:set_lanes (1, 1, 0) -- road always has this many lanes

      self.name = table_choose { "Range Road", "County Road" }
      self.name = self.name .. " " .. RN_index (999)

   end

    self.cur_event_type = 1
    self:add_event_segs (self.cur_event_type)
end

function roadstream:get_want_cars ()

   local TypeCars = { 100, 35, 5 }
   return TypeCars[self.type] * (1 + self.cur_lanes)
end

function roadstream:get_want_speed ()

   local TypeBases = { 90, 60, 40 }
   return clamp (TypeBases[self.type] * (1 + self.cur_lanes / 5), 30, 100)
end

function roadstream:set_lanes (Lanes, RLanes, Median)

   self.cur_lanes = Lanes
   self.cur_rlanes = RLanes
   self.cur_median = Median
end

function roadstream:next_seg ()

   -- return the next road segment
   while (sizeof (self.cur_segs) == 0) do self:next_event ()
   end

   local NextSeg = self.cur_segs[1]
   table.remove (self.cur_segs, 1)
   return NextSeg
end

function roadstream:next_event ()

   -- get the new event type
   local EventType = self:choose_next_event_type ()
   self:add_event_segs (EventType)
   self.cur_event_type = EventType
end

function roadstream:choose_next_event_type ()

   -- based on previous event, choose the next event
   local CurEventType = self.cur_event_type
   local EventType = nil
   if (not CurEventType) then

      -- initially, always go straight
      EventType = 1

   elseif (1 == CurEventType) then

      -- if we're going straight, then anything can happen
      local EventWeights = {}
      EventWeights[1] = 10 -- most likely, keep going straight

      -- depending on road type, terrain type, we could increase or decrease our lanes
      local MaxLanes = self:get_max_lanes ()
      if (self.cur_lanes < MaxLanes) then EventWeights[2] = 1
      end

      -- decrease our lanes?
      local MinLanes = self:get_min_lanes ()
      if (self.cur_lanes > MinLanes) then EventWeights[3] = 1
      end

      -- passing lane?
      if (1 == self.cur_lanes) then EventWeights[4] = 3
      end

      -- exit?
      if (self.cur_lanes > 1) then EventWeights[5] = 2
      end

      if (TEST_EXIT_NODE) then EventWeights[5] = 50
      end

      -- choose weighted
      EventType = set_choose_weighted (EventWeights)

   else

      -- just had a lane reduction, or passing lanes; go straight for awhile
      EventType = 1
   end

   return EventType
end

function roadstream:add_event_segs (EventType)

   -- now, based on the next event type chosen above, create the segs for it
   self.cur_segs = {}
   if (1 == EventType) then

      -- go straight
      local StraightLen = self:get_straight_len ()
      self:add_segs (StraightLen)

   elseif (2 == EventType) then

      -- increase lanes
      self.cur_lanes = self.cur_lanes + 1
      self.cur_rlanes = self.cur_rlanes + 1
      self:add_segs (5)

   elseif (3 == EventType) then

      -- decrease lanes
      self.cur_lanes = self.cur_lanes - 1
      self.cur_rlanes = self.cur_rlanes - 1
      self:add_segs (5)

   elseif (4 == EventType) then

      -- passing lanes
      local PassLen = self:get_pass_len ()
      local PassFlag = (RN () < 0.75)
      local RPassFlag = (RN () < 0.75)

      if (PassFlag) then

         -- our passing lane
         self.cur_lanes = self.cur_lanes + 1
         self:add_segs (self:get_pass_len ())
         self.cur_lanes = self.cur_lanes - 1
      end

      if (PassFlag and RPassFlag) then

         -- middle section
         self:add_segs (self:get_pass_len ())
      end

      if (RPassFlag) then

         -- the other guy's pass lane
         self.cur_rlanes = self.cur_rlanes + 1
         self:add_segs (self:get_pass_len ())
         self.cur_rlanes = self.cur_rlanes - 1
      end

   elseif (5 == EventType) then

      -- exit
      self.cur_lanes = self.cur_lanes + 1
      self:add_segs (4, 2) -- pre-exit
      self:add_segs (1, 3) -- exit
      self.cur_lanes = self.cur_lanes - 1
      self:add_segs (1) -- pre-overpass
      self:add_segs (1, 4) -- overpass

      -- exit always followed by entrance
      self:add_segs (1) -- post-overpass
      self.cur_lanes = self.cur_lanes + 1
      self:add_segs (1, 5) -- entrance
      self:add_segs (5) -- post exit/entrance
      self.cur_lanes = self.cur_lanes - 1
   end
end

function roadstream:get_max_lanes ()

   -- the maximum lanes per road type
   local MaxLanesPerType = { 4, 2, 1 }
   local MaxLanes = MaxLanesPerType[self.type]

   -- terrain also dictates to us
   local MaxLanesPerTerrain = { 4, 4, 1 }
   MaxLanes = math.max (MaxLanes, MaxLanesPerTerrain[self.terrain_type])

   return MaxLanes
end

function roadstream:get_min_lanes ()

   -- minimum lanes per road type
   local MinLanesPerType = { 2, 1, 1 }
   return MinLanesPerType[self.type]
end

function roadstream:get_straight_len ()

   -- how long to go straight for, depends mainly on road type
   local BasePerType = { 15, 10, 5 }
   local RangePerType = { 20, 10, 5 }
   local Base = BasePerType[self.type]
   local Range = RangePerType[self.type]

   -- also depends on terrain type
   local TerrainFactors = { 2.5, 1, 0.5 }
   Base = Base * TerrainFactors[self.terrain_type]
   Range = Range * TerrainFactors[self.terrain_type]

   return math.ceil ((RN_index (Range) + Base) / cur_play.compression)
end

function roadstream:get_pass_len ()

   -- how long we have to pass is dependant on terrain; mountains are unpredictable
   local BasePerTerrain = { 15, 15, 5 }
   local RangePerTerrain = { 0, 0, 10 }
   local Base = BasePerTerrain[self.terrain_type]
   local Range = RangePerTerrain[self.terrain_type]
   return math.ceil (RN_index (Range) + Base)
end


function roadstream:get_seg ()

   return roadseg (self.cur_lanes, self.cur_rlanes, self.cur_median)
end

temp_count = 1

function roadstream:add_segs (NumSegs, SegType)

   -- segtype is 1 == normal, 2 == pre-exit, 3 == exit, 4 == overpass, 5 == entrance
   SegType = nz (SegType, 1)

   -- if it's exit or preexit, then figure out the radius and spinout based on our type
   local TypeRadii = { 400, 200, 100 }
   local TypeSpinoutKPHs = { 100, 70, 50 }
   local Radius = TypeRadii[self.type]
   local SpinoutKPH = TypeSpinoutKPHs[self.type]

   -- help us choose what we should exit to
   local TypeExitSets = {

      { [node_city] = 2, [node_interchange] = 4, [node_service] = 3 },
      { [node_service] = 2, [node_town] = 4, [node_intersection] = 2 },
      { [node_intersection] = 2, [node_house] = 1 },
   }
   TypeExitSet = TypeExitSets[self.type]

   for i = 1, NumSegs, 1 do

      local Seg = self:get_seg ()
      if (2 == SegType) then Seg:set_lane_speed (Seg.lanes, SpinoutKPH)
      elseif (3 == SegType) then

         -- the exit itself; choose what we exit to based on the type
         local ExitNodeType = set_choose_weighted (TypeExitSet)
         if (TEST_EXIT_NODE) then ExitNodeType = TEST_EXIT_NODE
         end
         local ExitNode = ExitNodeType ()

         Seg:init_exit (Radius, SpinoutKPH, ExitNode)
         Seg:init_message (500, ExitNode.name .. " in 500m")
         temp_count = temp_count + 1

      elseif (4 == SegType) then Seg:init_overpass (2, 2, 2)
      elseif (5 == SegType) then Seg:init_entrance (Radius)
      end
      table.insert (self.cur_segs, Seg)
   end
end
