using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
// The 'windowHandle' parameter will contain the window handle for the:
//   - Active window when run by hotkey
//   - Trigger target when run by a Trigger rule
//   - TitleBar Button owner when run by a TitleBar Button
//   - Jump List owner when run from a Taskbar Jump List
//   - Currently focused window if none of these match
// 
// This function looks at physical monitor position (just X axis) and transfers window on first monitor on the LEFT
  //          Monitors setup on my Laptop when docked
  //+-------------------------+   +-------------------------+
  //|                         |   |                         |
  //|                         |   |                         |
  //|  Monitor 2 (1680x1050)  |   |  Monitor 3 (1680x1050)  |
  //|                         |   |                         |
  //|                         |   |                         |
  //|                         |   |                         |
  //+-------------------------+   +-------------------------+
  //         +------------------------------+
  //         |                              |
  //         |                              |
  //         |    Monitor 1  (1920x1080)    |
  //         |                              |
  //         |                              |
  //         |                              |
  //         +------------------------------+
// when invoked on monitor 1 it will transfer window on monitor 2
// when invoked on monitor 2 it will transfer window on monitor 3
// when invoked on monitor 3 it will transfer window on monitor 1
public static class DisplayFusionFunction
{
	public static void Run(IntPtr windowHandle)
	{
      var mhor = new MonitorsHorizontalOrder();
      uint handleMonitor = BFS.Monitor.GetMonitorIDByWindow(windowHandle);
      uint targetMonitor = mhor.GetMonitorOnTheLeft(handleMonitor);
      if (handleMonitor != targetMonitor)
      {
        BFS.Window.MoveToMonitorMaximized(targetMonitor, windowHandle);
      }
	}
}
  [Serializable]
  public class WindowBoundsInfo
  {
    public uint MonitorID { get; set; }
    public Rectangle Bounds { get; set; }
    public WindowBoundsInfo(uint monID)
    {
      this.Bounds = BFS.Monitor.GetMonitorBoundsByID(monID);
      this.MonitorID = monID;
    }
  }
  public class MonitorsHorizontalOrder
  {
    private List<WindowBoundsInfo> monitorOrderedBounds;
    public MonitorsHorizontalOrder()
    {
      var monitorIds = BFS.Monitor.GetMonitorIDs();
      GetInfoAndOrderMonitorsHorizontally(monitorIds);
    }
    
    public MonitorsHorizontalOrder(IEnumerable<uint> monitorIds)
    {
      GetInfoAndOrderMonitorsHorizontally(monitorIds);
    }
    private void GetInfoAndOrderMonitorsHorizontally(IEnumerable<uint> monitorIds)
    {
      this.monitorOrderedBounds = monitorIds.Select(mid => new WindowBoundsInfo(mid)).OrderBy(wbi => wbi.Bounds.Left).ToList();
    }
    public uint GetMonitorOnTheLeft(uint monID)
    {
      var index = GetMonitorIndexInList(monID);
      if (index.HasValue)
      {
        if (index.Value > 0)
        {
          return this.monitorOrderedBounds[index.Value - 1].MonitorID;
        }
        else
        {
          return this.monitorOrderedBounds.Last().MonitorID;
        }
      }
      // fail safe 
      return monID;
    }
    public uint GetMonitorOnTheRight(uint monID)
    {
      var index = GetMonitorIndexInList(monID);
      if (index.HasValue)
      {
        if (index.Value == this.monitorOrderedBounds.Count-1)
        {
          return this.monitorOrderedBounds.First().MonitorID;
        }
        else
        {
          return this.monitorOrderedBounds[index.Value + 1].MonitorID;
        }
      }
      // default 
      return monID;
    }
    private int? GetMonitorIndexInList(uint monID)
    {
      int? index = null;
      var currentInfo = this.monitorOrderedBounds.FirstOrDefault(wbi => wbi.MonitorID == monID);
      if (currentInfo != null)
      {
        index = this.monitorOrderedBounds.IndexOf(currentInfo);
      }
      return index;
    }
  }