local row_height, scroll_rows, em, w, h
local padding, buffer_padding, scroll_point = 10, 0, 0.8

local function setColor255(r,g,b,a)
   if g then 
      if a then 
         love.graphics.setColor(
            mc(0,r/255,1),
            mc(0,g/255,1),
            mc(0,b/255,1),
            mc(0,a/255,1)
         )
      else
         love.graphics.setColor(
            mc(0,r/255,1),
            mc(0,g/255,1),
            mc(0,b/255,1)
         )
      end
   else
      if r[4] then 
         love.graphics.setColor(
            mc(0,r[1]/255,1),
            mc(0,r[2]/255,1),
            mc(0,r[3]/255,1),
            mc(0,r[4]/255,1)
         )
      else
         love.graphics.setColor(
            mc(0,r[1]/255,1),
            mc(0,r[2]/255,1),
            mc(0,r[3]/255,1)
         )
      end
   end
end

local render_line = function(ln2, y, n)
   if(ln2 == "\f\n" or ln2 == "\f") then
      love.graphics.line(0, y + 0.5 * row_height, w, y + 0.5 * row_height)
   else
      setColor255(scriptsPanel.buffer.gutterColor)
      love.graphics.printf(n, buffer_padding-scriptsPanel.buffer.gutterWidth-8,y,scriptsPanel.buffer.gutterWidth,"right")
      setColor255(255,255,255,255)


      love.graphics.print(ln2, buffer_padding, y)
   end
end


local render_buffer = function(b, colors, x, y, bw, bh, focused)

   local display_rows = math.floor(bh / row_height)
   local edge = math.ceil(display_rows * scroll_point)
   local offset = (b.point_line < edge and 0) or (b.point_line - edge)
   local ends = scriptsPanel.buffer.ends
   if(focused or not scroll_rows) then scroll_rows = display_rows end
   scriptsPanel.buffer.lines = b.props.render_lines or b.lines
   scriptsPanel.buffer.d = row_height
   em = scriptsPanel.buffer.em
   local draw =  function(line, row_y,n)
      if(b.props.render_lines) then -- fancy colors get ANDed w base colors
            setColor255(255, 255, 255)
         else
            love.graphics.setColor(colors.text)
         end
         render_line(line, row_y,n)
      end
      local outline =  {}
      scriptsPanel.buffer.maxw= 48*em
   for i,line in ipairs(b.props.render_lines or b.lines) do
      if(i >= offset) then
         local row_y = row_height * (i - offset)
         
         local lw = love.graphics.getFont():getWidth(tostring(b.lines[i]))
         if lw+9*em>scriptsPanel.buffer.maxw then
            scriptsPanel.buffer.maxw=lw+9*em
         end
         if(row_y >= h - row_height) then break end

         if(i == b.mark_line)  then -- mark
            setColor255(scriptsPanel.buffer.markColor)
            love.graphics.rectangle("fill", b.mark*em, row_y, 2, row_height)
         end

         if ends then
            draw(line, row_y,i)
            gfx.setBlendMode('screen')
            setColor255(scriptsPanel.buffer.fillColor)
            if i==ends[1] and i==ends[3] then 
             outline={
               buffer_padding+ends[2]*em, row_y,
               buffer_padding+ends[4]*em, row_y,
               buffer_padding+ends[4]*em, row_y+row_height,
               buffer_padding+ends[2]*em, row_y+row_height
             }
             love.graphics.rectangle("fill", buffer_padding+ends[2]*em, row_y+1, (ends[4]-ends[2])*em, row_height)
             elseif i>ends[1] and i<ends[3]then
               outline=lume.concat(
                  outline,
                  {buffer_padding+lw,row_y},
                  {buffer_padding+lw,row_y+row_height}
               )
               love.graphics.rectangle("fill", buffer_padding, row_y+1, lw, row_height)
            elseif i==ends[1] then
               outline=lume.concat(
                  outline, 
                  {buffer_padding,row_y+(ends[2]==0 and 0 or row_height)},
                  {buffer_padding+(lw==0 and em or ends[2]*em),row_y+(lw==0 and 0 or row_height)},
                  {buffer_padding+(lw==0 and em or ends[2]*em),row_y},
                  {buffer_padding+ (lw==0 and em or lw),row_y},
                  {buffer_padding+ (lw==0 and em or lw),row_y+row_height}
               )
               love.graphics.rectangle("fill", buffer_padding+ends[2]*em, row_y+1, lw-ends[2]*em, row_height)
            elseif i==ends[3] then
               outline=lume.concat(
                  outline, 
                  {buffer_padding+ends[4]*em,row_y},
                  {buffer_padding+ends[4]*em,row_y+row_height},
                  {buffer_padding,row_y+ (ends[4]==0 and 0 or row_height)}
               )
               love.graphics.rectangle("fill", buffer_padding, row_y+1, ends[4]*em, row_height)
             end
              gfx.setBlendMode('alpha')
         end

         if(i == b.point_line)   then -- point and point line
            if not ends     then 
               setColor255(33/2,39/2,51/2,100*scriptsPanel.buffer.alpha)
               love.graphics.rectangle("fill", -2, row_y+1, w-16+2, row_height)
            end
           
            if  (i == b.point_line) then
               setColor255(scriptsPanel.buffer.cursorColor)
               love.graphics.rectangle(focused and "fill" or "line",
                                       buffer_padding+b.point*em-1, row_y,
                                       2, row_height+2)
            end
            
         end
         if not ends then 
          draw(line, row_y,i)
         end
      end
   end
   if #outline>0 then 
      gfx.setLineWidth(1) 
      gfx.setLineJoin("none")
      gfx.setBlendMode("screen")
       --if ends[1]~=ends[3] then
         outline = lume.concat(outline,{outline[1],outline[2]})
         setColor255(scriptsPanel.buffer.outlineColor)
         --gfx.line(outline)
      --end
      setColor255(scriptsPanel.buffer.fillColor)
      local success,tris = pcall(love.math.triangulate,outline)
      if success then 
         for i,tri in ipairs(tris) do 
           -- gfx.polygon("fill",tri) 
         end
      end
      gfx.setBlendMode("alpha")
      gfx.setLineJoin("miter")
   end
end

local draw_scroll_bar = function(b, colors)
   -- this only gives you an estimate since it uses the amount of
   -- lines entered rather than the lines drawn, but close enough

   -- height is percentage of the possible lines
   local bar_height = math.min(100, (scroll_rows * 100) / #b.lines)
   -- convert to pixels (percentage of screen height, minus 10px padding)
   local bar_height_pixels = (bar_height * (h - 10)) / 100

   local sx = x2+w - 5
   love.graphics.setColor(colors.scroll_bar)
   -- Handle the case where there are less actual lines than display rows
   if bar_height_pixels >= h - 10 then
      --love.graphics.line(sx, y2+5, sx, h - y2+5)
   else
      -- now determine location on the screen by taking the offset in
      -- history and converting it first to a percentage of total
      -- lines and then a pixel offset on the screen
      local bar_end = (b.point_line * 100) / #b.lines
      bar_end = ((h - 10) * bar_end) / 100

      local bar_begin = bar_end - bar_height_pixels
      -- Handle overflows
      if bar_begin < y2+5 then
         love.graphics.line(sx, y2+5, sx, bar_height_pixels)
      elseif bar_end > h - y2+5 then
         love.graphics.line(sx, h - y2+5 - bar_height_pixels, sx, h - y2+5)
      else
         love.graphics.line(sx, bar_begin, sx, bar_end)
      end
   end
end

return function(b, buffers_where, echo_message, colors, get_prop)
   row_height = love.graphics.getFont():getHeight()
   em = love.graphics.getFont():getWidth('a')
   w, h = scriptsPanel.buffer.w or w,2000
   x2, y2 = scriptsPanel.buffer.x,scriptsPanel.buffer.y-row_height

   -- Draw background
   if(#buffers_where > 0) then
      --setColor255(colors.background)
      --love.graphics.rectangle("fill", 0, 0, w, h)
   end

   for pos,buf in pairs(buffers_where) do
      local x,y,bw,bh = unpack(pos)
      love.graphics.push()
      love.graphics.translate(x+x2, y+y2)
      --love.graphics.intersectScissor(x+x2-scriptsPanel.buffer.gutterWidth-4, y+y2, w, h)
      if(get_prop("draw", nil, buf)) then
         get_prop("draw", nil, buf)()
      else
         render_buffer(buf, colors, x+x2, y+y2, w, h, buf == b)
      end
      love.graphics.pop()
      --love.graphics.intersectScissor()
   end

   --[[setColor255(colors.minibuffer_bg)
   love.graphics.rectangle("fill", 0, h - row_height, w, row_height)
   setColor255(colors.minibuffer_fg)

   if(b.path == "minibuffer") then
      love.graphics.print(b:render(), padding, h - row_height)
      setColor255(colors.point)
      love.graphics.rectangle("fill", padding+b.point*em,
                              h - row_height, em, row_height)
   elseif(echo_message) then
      love.graphics.print(echo_message, padding, h - row_height)
   else
      love.graphics.print(b:modeline(), padding, h - row_height)
   end]]

   if(b.path ~= "minibuffer") then draw_scroll_bar(b, colors) end
end
