#!/bin/python3
from argparse import ArgumentParser
import subprocess
import json 

enter="\n"

# Returns a list of all json window objects
def get_windows():

    command="swaymsg -t get_tree"
    
    active_outputs = []
    
    process = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    data = json.loads(process.communicate()[0])

    # Select outputs that are active
    windows = []
    for output in data['nodes']:

        # The scratchpad (under __i3) is not supported
        if output.get('name') != '__i3' and output.get('type') == 'output':
                workspaces = output.get('nodes')
                for ws in workspaces:
                    if ws.get('type') == 'workspace':
                        windows += extract_nodes_iterative(ws)
    return windows

# Extracts all windows from a sway workspace json object 
def extract_nodes_iterative(workspace):
    all_nodes = []
    
    floating_nodes = workspace.get('floating_nodes')

    for floating_node in floating_nodes:
        all_nodes.append(floating_node)

    nodes = workspace.get('nodes')
    
    for node in nodes:

        # Leaf node
        if len(node.get('nodes')) == 0:
            all_nodes.append(node)
        # Nested node, handled iterative
        else:
            for inner_node in node.get('nodes'):
                nodes.append(inner_node)

    return all_nodes

# Returns an array of all windows
def parse_windows(windows):
    parsed_windows = []
    for window in windows:
        parsed_windows.append(window.get('name'))
    return parsed_windows

# Returns a newline seperated UFT-8 encoded string of all windows for wofi
def build_wofi_string(windows):
    return enter.join(windows).encode("UTF-8")

# Executes wofi with the given input string
def show_wofi(windows):

    command="wofi -c ~/.config/wofi/menu -s ~/.config/wofi/sway.css -p \"Windows: \" -d -i --hide-scroll"
    
    process = subprocess.Popen(command,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
    return process.communicate(input=windows)[0]

# Returns the sway window id of the window that was selected by the user inside wofi
def parse_id(windows, parsed_windows, selected):
    selected = (selected.decode("UTF-8"))[:-1] # Remove new line character
    window_index = int(parsed_windows.index(selected)) # Get index of selected window in the parsed window array
    return str(windows[window_index].get('id')) # Get sway window id based on the index

# Switches the focus to the given id
def switch_window(id):
    command="swaymsg [con_id={}] focus".format(id)
    
    process = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE)
    process.communicate()[0]

# Entry point
if __name__ == "__main__":
    
    parser = ArgumentParser(description="Wofi based window switcher")

    windows = get_windows()
    
    parsed_windows = parse_windows(windows)    
    
    wofi_string = build_wofi_string(parsed_windows)

    selected = show_wofi(wofi_string)
    
    selected_id = parse_id(windows, parsed_windows, selected)

    switch_window(selected_id)
