
import sys
import os
import socket
import clr
import System
import time
from System.CodeDom.Compiler import CodeDomProvider, CompilerParameters
from System.IO import File, Path, Directory

PORTS_TO_SCAN = [56000, 52000, 65000, 3010, 3011, 3012, 3013]
HOST = "127.0.0.1"

CS_SOURCE = """
using System;
using com.omnesys.rapi;

namespace RithmicWrapper {
    public class AdmCallbacks : com.omnesys.rapi.AdmCallbacks {
        public override void Alert(AlertInfo oInfo) {
            Console.WriteLine("[Wrapper] AdmAlert received");
        }
    }

    public class RCallbacks : com.omnesys.rapi.RCallbacks {
        public override void Alert(AlertInfo oInfo) {
            Console.WriteLine("[Wrapper] RAlert received");
        }
    }
}
"""

def scan_ports():
    print(f"Scanning ports on {HOST}...")
    open_ports = []
    for port in PORTS_TO_SCAN:
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.settimeout(0.5)
                result = s.connect_ex((HOST, port))
                if result == 0:
                    print(f"  [OPEN] {port}")
                    open_ports.append(port)
                else:
                    print(f"  [CLOSED] {port}")
        except Exception as e:
            print(f"  [ERROR] {port}: {e}")
    return open_ports

def compile_wrapper(libs_dir):
    print("Compiling C# wrapper...")
    rapi_dll = os.path.join(libs_dir, "rapiplus.dll")
    
    provider = CodeDomProvider.CreateProvider("CSharp")
    params = CompilerParameters()
    params.GenerateInMemory = True
    params.ReferencedAssemblies.Add("System.dll")
    params.ReferencedAssemblies.Add(rapi_dll)
    
    results = provider.CompileAssemblyFromSource(params, CS_SOURCE)
    
    if results.Errors.HasErrors:
        print("Wrapper Compilation Failed:")
        for err in results.Errors:
            print(f"  {err}")
        return None
        
    print("Wrapper Compilation Success!")
    return results.CompiledAssembly

def setup_dll():
    # DLLロード処理
    current_dir = os.getcwd()
    script_dir = os.path.dirname(os.path.abspath(__file__))
    project_root = os.path.dirname(script_dir)
    
    possible_libs = [
        os.environ.get("RAPI_DLL_DIR", "C:\\temp\\RithmicBridgeTemp"),
        r"C:\Program Files (x86)\Rithmic\Rithmic Trader Pro",
        os.path.join(current_dir, "libs"),
        os.path.join(project_root, "libs"),
    ]
    
    libs_dir = None
    for p in possible_libs:
        if os.path.exists(p) and os.path.exists(os.path.join(p, "rapiplus.dll")):
            libs_dir = p
            break
            
    if not libs_dir:
        print("ERROR: libs directory not found.")
        return None, None

    print(f"Using libs from: {libs_dir}")
    sys.path.append(libs_dir)
    
    if hasattr(os, 'add_dll_directory'):
        os.add_dll_directory(libs_dir)
    
    os.environ['PATH'] = libs_dir + os.pathsep + os.environ['PATH']
    
    dll_path = os.path.join(libs_dir, "rapiplus.dll")
    
    original_cwd = os.getcwd()
    try:
        os.chdir(libs_dir)
        try:
            System.Reflection.Assembly.LoadFrom(dll_path)
            clr.AddReference("rapiplus")
        except Exception as e:
            print(f"LoadFrom Failed: {e}")
            try:
                clr.AddReference("rapiplus")
            except Exception as e2:
                print(f"AddReference Failed: {e2}")
                return None, None
        
        try:
            import com.omnesys.rapi as rapi
            
            # ここでコンパイル
            wrapper_assembly = compile_wrapper(libs_dir)
            
            return rapi, wrapper_assembly
        except ImportError as e:
            print(f"Import Error: {e}")
            return None, None
    finally:
        os.chdir(original_cwd)

def test_rapi_connect(rapi, wrapper_assembly, port):
    print(f"\nTesting R|API+ connection to {HOST}:{port}...")
    try:
        if wrapper_assembly is None:
            print("Wrapper assembly is needed but not available.")
            return False

        # Wrapperクラスのインスタンス化
        # 名前空間.クラス名 で取得
        adm_cb_type = wrapper_assembly.GetType("RithmicWrapper.AdmCallbacks")
        r_cb_type = wrapper_assembly.GetType("RithmicWrapper.RCallbacks")
        
        adm_cb = System.Activator.CreateInstance(adm_cb_type)
        r_cb = System.Activator.CreateInstance(r_cb_type)

        params = rapi.REngineParams()
        params.AppName = "TestConnectWin"
        params.AppVersion = "1.0.0"
        params.LogFilePath = os.path.abspath("test_rapi_win.log")
        
        addr = f"{HOST}:{port}"
        params.DmnSrvrAddr = addr
        params.DomainName = "rithmic_paper_domain" # Correct Env Key from logs
        params.LicSrvrAddr = addr
        params.LocBrokAddr = addr
        params.LoggerAddr = addr
        
        params.AdmCallbacks = adm_cb

        print("  Initializing REngine...")
        engine = rapi.REngine(params)
        print("  -> REngine Instantiation: SUCCESS")
        
        user = os.environ.get("RITHMIC_USER", "dummy")
        pwd = os.environ.get("RITHMIC_PASSWORD", "dummy")
        
        print(f"  Login attempt to {addr}...")
        
        # Plugin Mode Login
        engine.login(r_cb, "test", user, pwd, addr, "test", user, pwd, addr, addr, "test", user, pwd, addr)
        print("  -> Login command sent. Waiting for 3 seconds...")
        
        time.sleep(3)
        
        engine.shutdown()
        print("  -> Shutdown.")
        return True
            
    except Exception as e:
        print(f"  -> RAPI Error: {e}")
        import traceback
        traceback.print_exc()
        return False

if __name__ == "__main__":
    open_ports = scan_ports()
    if not open_ports:
        print("No open ports found.")
    else:
        rapi_mod, wrapper_asm = setup_dll()
        if rapi_mod and wrapper_asm:
            for port in open_ports:
                test_rapi_connect(rapi_mod, wrapper_asm, port)
        else:
            print("Skipping RAPI connection test due to DLL/Wrapper load failure.")
