import os
import ctypes
import shutil
from subprocess import PIPE, Popen


class disable_file_system_redirection:
    _disable = ctypes.windll.kernel32.Wow64DisableWow64FsRedirection
    _revert = ctypes.windll.kernel32.Wow64RevertWow64FsRedirection

    def __enter__(self):
        self.old_value = ctypes.c_long()
        self.success = self._disable(ctypes.byref(self.old_value))

    def __exit__(self, type, value, traceback):
        if self.success:
            self._revert(self.old_value)


url = itsm.getParameter('Imagelist')  # Provide an image URLS which you want to set as Screen Saver.the datatype
# should be a list.url must be a direct download.
idlTime = itsm.getParameter('idealTime')  # Provide the ideal time only in minutes(if ideal time is 1 the screen saver
# starts when the pc is ideal for more the 1 minute), the data type should be int.

imgDir = os.environ['TEMP'] + r'\ScreenSaver'
ScreenSaverPAth = os.path.expanduser('~') + r'\ScreenSaver.scr'

# with disable_file_system_redirection():
#     userout = os.popen('query user').read()
#     username = re.sub('^ ', '', re.findall("(.*)Active", userout)[0].split('  ')[0].replace('>', ''))
#     sid = os.popen("wmic useraccount where name=\"%s\" get sid" % username).read().splitlines()[1].strip()


ScreenSaver = r'''
#requires -Version 3

<#
    .SYNOPSIS
    .DESCRIPTION
    .EXAMPLE
#>

Set-StrictMode -Version 2.0

$source = @'
namespace SimpleScreensaver
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Media.Imaging;
    using System.Windows.Threading;
    public class SimpleScreensaver : Window
    {
        private const int BaseDisplayTime = ###timeout###;
        private static readonly IList<BitmapImage> Images = new List<BitmapImage>();
        [STAThread]
        public static void Main(string[] args)
        {
            var arg1 = string.Empty;
            var arg2 = string.Empty;
            if (args.Length > 0)
            {
                var splitArgs = args[0].Split(':');
                arg1 = splitArgs[0].ToLower().Trim();
                if (splitArgs.Length > 1)
                {
                    // examples /p:1234 or /c:1234
                    arg2 = splitArgs[1].ToLower().Trim();
                }
                else if (args.Length > 1)
                {
                    // examples /p 1234 or / c 1234
                    arg2 = args[1].ToLower().Trim();
                }
            }
            switch (arg1)
            {
                case "/s":
                    // show screensaver
                    ShowScreensaver();
                    break;
                case "/p":
                    // show the preview window
                    // Not implemented
                    break;
                default:
                    // show config, covers the /c option too
                    // Not implemented
                    break;
            }
        }
        private static void ShowScreensaver()
        {
            // load images
            var slides = new[]
                             {
                                 ###images###
                             };
            foreach (var slide in slides)
            {
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(slide))
                {
                    if (stream == null)
                    {
                        continue;
                    }
                    var image = new BitmapImage();
                    var result = new byte[stream.Length];
                    stream.Read(result, 0, (int)stream.Length);
                    image.BeginInit();
                    image.StreamSource = new MemoryStream(result);
                    image.EndInit();
                    Images.Add(image);
                }
            }
            // start screensaver on each screen
            var app = new Application();
            var screenCount = 0;
            var random = new Random();
            foreach (var screen in System.Windows.Forms.Screen.AllScreens)
            {
                // set the display time to the base time + offset so multiple screens 
                // change images at different times
                // send the screen count so each screen has a different slide
                // it just looks nicer
                var window = new SimpleScreensaver(
                    screen.Bounds, screenCount, BaseDisplayTime + random.Next(BaseDisplayTime / 2));
                window.Show();
                ++screenCount;
            }
            app.Run();
        }
        /** 
         *    
         *  Screensaver
         *    
         **/
        private readonly Storyboard fadeOut;
        private readonly Storyboard fadeIn;
        private readonly Image slide;
        private int nextSlide;
        private bool mouseMoved;
        private Point mousePosition;
        private SimpleScreensaver(System.Drawing.Rectangle bounds, int startSlide, int displayTime)
        {
            //
            // Window setup
            //
            this.Title = "Simple Screensaver";
            this.Background = Brushes.Black;
            this.WindowStyle = WindowStyle.None;
            this.ResizeMode = ResizeMode.NoResize;
            this.WindowStartupLocation = WindowStartupLocation.Manual;
            this.Top = bounds.Top;
            this.Left = bounds.Left;
            this.Height = bounds.Height;
            this.Width = bounds.Width;
            this.Cursor = Cursors.None;
            this.Topmost = true;
            //
            // Set first slide
            //
            this.nextSlide = startSlide % Images.Count;
            //
            // Events 
            //
            this.KeyDown += this.Window_KeyDown;
            this.MouseDown += this.Window_MouseDown;
            this.MouseMove += this.Window_MouseMove;
            //
            // Add controls to window
            //
            this.slide = new Image
            {
                Name = "slide",
                Stretch = Stretch.Uniform,
                Margin = new Thickness(0),
            };
            var grid = new Grid();
            grid.Children.Add(this.slide);
            this.Content = grid;
            //
            // Setup fade in/fade out actions
            //
            var fadeInAnimation = new DoubleAnimation
            {
                From = 0,
                To = 1,
            };
            Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(OpacityProperty));
            this.fadeIn = new Storyboard();
            this.fadeIn.Children.Add(fadeInAnimation);
            var fadeOutAnimation = new DoubleAnimation
            {
                From = 1,
                To = 0,
                Duration = new Duration(TimeSpan.FromSeconds(2))
            };
            Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath(OpacityProperty));
            this.fadeOut = new Storyboard();
            if (Images.Count > 1)
            {
                this.fadeOut.Children.Add(fadeOutAnimation);
            }
            this.fadeOut.Completed += this.FadeOut_Completed;
            //
            // Setup timer
            //
            var timer = new DispatcherTimer();
            timer.Tick += this.Timer_Tick;
            timer.Interval = new TimeSpan(0, 0, displayTime);
            timer.Start();
            //
            // Trigger first image
            //
            this.FadeOut_Completed(null, EventArgs.Empty);
        }
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            Application.Current.Shutdown();
        }
        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Application.Current.Shutdown();
        }
        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            var position = e.GetPosition(this);
            if (this.mouseMoved)
            {
                // only close out if the mouse moved enough
                if (Math.Abs(this.mousePosition.X - position.X) > 50 || Math.Abs(this.mousePosition.Y - position.Y) > 50)
                {
                    Application.Current.Shutdown();
                }
            }
            else
            {
                this.mouseMoved = true;
                this.mousePosition = position;
            }
        }
        private void FadeOut_Completed(object sender, EventArgs e)
        {
            this.slide.BeginInit();
            this.slide.Source = Images[this.nextSlide];
            this.slide.EndInit();
            this.nextSlide = (this.nextSlide + 1) % Images.Count;
            // fade in the new image
            if(Images.Count > 1)
            {
             this.fadeIn.Begin(this.slide);
            }
        }
        private void Timer_Tick(object sender, EventArgs e)
        {
            // after fade out is complete it will 
            // trigger the event to switch to the next slide
            this.fadeOut.Begin(this.slide);
        }
    }
}
'@

function New-Screensaver 
{
    Add-Type -AssemblyName PresentationFramework
    $provider = New-Object -TypeName Microsoft.CSharp.CSharpCodeProvider
    $provider = [Microsoft.CSharp.CSharpCodeProvider]::CreateProvider('CSharp')

    $cp = New-Object -TypeName System.CodeDom.Compiler.CompilerParameters
    $cp.GenerateExecutable = $true
    $cp.OutputAssembly = "#SSLOC#"
    $cp.IncludeDebugInformation = $false

    $cp.ReferencedAssemblies.Add('System.dll')
    $cp.ReferencedAssemblies.Add('System.Xaml.dll')
    $cp.ReferencedAssemblies.Add('System.Drawing.dll')
    $cp.ReferencedAssemblies.Add('System.Windows.Forms.dll')

    [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object -Process {
        if($_.FullName -match 'PresentationCore' -or
           $_.FullName -match 'PresentationFramework' -or
           $_.FullName -match 'WindowsBase' ) 
        {
            $cp.ReferencedAssemblies.Add($_.Location)
        }
    }

    $cp.GenerateInMemory = $false
    $cp.WarningLevel = 3
    $cp.TreatWarningsAsErrors = $false
    $cp.CompilerOptions = '/optimize /target:winexe'
    $cp.TempFiles = New-Object -TypeName System.CodeDom.Compiler.TempFileCollection -ArgumentList ($env:TEMP, $false)

    # Add images as resources 
    $resList = @()
    $folderProps = @{'Path' = (Join-Path -Path #IMGDIR# -ChildPath '*');
                     'Include' = @('*.jpg','*.jpeg','*.bmp','*.gif','*.png')
                    }
    foreach($file in (Get-ChildItem @folderProps | Sort-Object -Property Name))
    {
        $cp.EmbeddedResources.Add($file.FullName.ToLower())
        $resList += '"{0}"' -f $file.Name.ToLower()
    }

    $srcFile = Join-Path -Path $env:TEMP -ChildPath 'screensaver.cs'

    $tmpSource = $source -replace '###timeout###', #TIME#
    $tmpSource = $tmpSource -replace '###images###', ($resList -join ',')
    $tmpSource | Out-File -FilePath $srcFile -Force

    $result = $provider.CompileAssemblyFromFile($cp, $srcFile)

    Remove-Item -Path $srcFile -Force -ErrorAction SilentlyContinue

    if($result.NativeCompilerReturnValue -eq 0)
    {
        Write-Output "Screensaver built successfully"
    } else {
        Write-Output $result.errors
        Write-Output "Screensaver build failed"
    }
}
New-Screensaver 
'''

setScreenSaver = r'''
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v SCRNSAVE.EXE /t REG_SZ /d "''' + ScreenSaverPAth + r'''" /f
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v ScreenSaveActive /t REG_SZ /d 1 /f
'''

SetonResume = r'''
Function Set-ScreenSaver() {
Add-Type -TypeDefinition @" 
using System; 
using System.Runtime.InteropServices;

public class Params
{ 
    [DllImport("User32.dll",CharSet=CharSet.Unicode)] 
    public static extern int SystemParametersInfo (Int32 uAction, 
                                                   Int32 uParam, 
                                                   String lpvParam, 
                                                   Int32 fuWinIni);
}
"@ 
    $UpdateIniFile = 0x01
    $SendChangeEvent = 0x02
    $fWinIni = $UpdateIniFile -bor $SendChangeEvent
    $ret = [Params]::SystemParametersInfo(119, 1, '', $fWinIni)
	$timeOut = [Params]::SystemParametersInfo(15, ''' + str(idlTime * 60) + r''', '', 0)
    if($ret -eq 1){
        Write-Output "ScreenSaver has been set successfully"
    }
}

Set-ScreenSaver
'''


def eCmd(command):
    with disable_file_system_redirection():
        obj = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
    out, err = obj.communicate()
    print err
    if err == '' and "successfully" in out:
        return True
    else:
        return False


def Downloadimages(imageLoc):
    try:
        for img in imageLoc:
            Download_path = imgDir + '\\' + os.path.basename(img)

            Dwn_content = r''' 
            $url = "''' + img + '''"

            $wc = New-Object System.Net.WebClient
            $wc.DownloadFile($url, "''' + Download_path + '''")
            '''
            DownScript = CreateScriptFile(Dwn_content)
            if os.path.exists(DownScript):
                eCmd('powershell "%s"' % DownScript)
    except:
        pass


def CreateScriptFile(ps_content):
    try:
        file_name = 'ScriptFile.ps1'
        file_path = os.path.join(os.environ['TEMP'], file_name)
        with open(file_path, 'wb') as wr:
            wr.write(ps_content)
            wr.close()
        return file_path
    except:
        return None


def exeSF(scriptCnt, Process, VFlag):
    ScriptFile = CreateScriptFile(scriptCnt)
    if os.path.exists(ScriptFile):
        if eCmd('powershell "%s"' % ScriptFile):
            if VFlag:
                print 'Script execution successful [' + Process + ']'
                return True
        else:
            if VFlag:
                print 'Script execution failed [' + Process + ']'
                return False
    else:
        print 'Script file creation failed [' + Process + ']'
        return False


def SetScreensaver(ssContent):
    try:
        try:
            shutil.rmtree(imgDir)
        except:
            pass
        with open(ScreenSaverPAth, 'w') as fp:
            pass
        os.makedirs(imgDir)
        eCmd('powershell "Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"')
        Downloadimages(url)
        if len(os.listdir(imgDir)) != 0:
            print "File downloaded successfully"
            if os.path.exists(ScreenSaverPAth):
                ssContent = ssContent.replace("#IMGDIR#", imgDir).replace("#TIME#", "10").replace("#SSLOC#",
                                                                                                  ScreenSaverPAth)
                if exeSF(ssContent, 'Build Screensaver', True):
                    if exeSF(setScreenSaver, 'Set Screensaver', True):
                        exeSF(SetonResume, 'Set Screensaver', False)
                        print '\nProcess Completed'
                    else:
                        print '\nProcess Failed'
                else:
                    print '\nProcess Failed'
            else:
                print "Failed to create screen saver temp file"
            #shutil.rmtree(imgDir)
        else:
            print "Download failed"
    except:
        print 'Process failed'


SetScreensaver(ScreenSaver)
