Imports System.Xml.Linq
Imports System.Windows.Data
Imports System.Globalization
Imports C1.Silverlight
Imports C1.Silverlight.Maps
Imports System.Windows.Threading

Public Partial Class Flicker
    Inherits UserControl
    Private _timer As DispatcherTimer

    Public Sub New()
        InitializeComponent()
        AddHandler Me.Loaded, AddressOf Flicker_Loaded
        AddHandler Me.Unloaded, AddressOf Flicker_Unloaded
        InitialMaps()
    End Sub

    Private Sub Flicker_Unloaded(sender As Object, e As RoutedEventArgs)
        If _timer IsNot Nothing Then
            _timer.[Stop]()
        End If
        maps.TargetCenter = New Point(0, 0)
    End Sub

    Private Sub InitialMaps()
        If maps IsNot Nothing Then
            maps.Zoom = 4
            If maps.Layers Is Nothing Or maps.Layers.Count = 0 Then
                Dim layer As New C1VectorLayer() With {
                    .Name = "v1",
                    .LabelVisibility = LabelVisibility.Visible,
                    .ItemStyle = DirectCast(Me.Resources("style"), Style),
                    .UriSource = New Uri("http://api.flickr.com/services/feeds/geo/Uruguay/Montevideo")
                }
                AddHandler layer.UriSourceLoaded, AddressOf vl_UriSourceLoaded
                maps.Layers.Add(layer)
            End If
            vl = TryCast(maps.Layers(0), C1VectorLayer)

            AddHandler vl.UriSourceLoaded, Sub(s, ve)
                                               Dispatcher.BeginInvoke(Sub()
                                                                          txt.Visibility = Visibility.Collapsed
                                                                          maps.Opacity = 1
                                                                          btnLoad.IsEnabled = InlineAssignHelper(tb.IsEnabled, True)
                                                                          _timer.Start()

                                                                      End Sub)

                                           End Sub
            AddHandler vl.UriSourceFailed, Sub(s, ve)
                                               Dispatcher.BeginInvoke(Sub()
                                                                          txt.Text = "Can't load data."
                                                                          btnLoad.IsEnabled = InlineAssignHelper(tb.IsEnabled, True)

                                                                      End Sub)

                                           End Sub

            ' shuffle images in z-order
            _timer = New DispatcherTimer() With {
                .Interval = TimeSpan.FromSeconds(0.5)
            }
            AddHandler _timer.Tick, Sub(s, te)
                                        Dim cnt As Integer = vl.Children.Count
                                        If cnt >= 2 Then
                                            vl.BeginUpdate()

                                            Dim item As C1VectorItemBase = vl.Children(0)
                                            vl.Children.RemoveAt(0)
                                            vl.Children.Add(item)

                                            vl.EndUpdate()
                                        End If

                                    End Sub

            AddHandler btnLoad.IsEnabledChanged, Sub(s, le)
                                                     btnLoad.Content = If(btnLoad.IsEnabled, "Load", "Loading...")

                                                 End Sub
        End If
    End Sub
    Private Sub Flicker_Loaded(sender As Object, e As RoutedEventArgs)
        InitialMaps()
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        If Not String.IsNullOrEmpty(tb.Text) Then
            Dim source As String = String.Format("http://api.flickr.com/services/feeds/geo/{0}", tb.Text)
            If vl IsNot Nothing Then
                _timer.[Stop]()
                vl.UriSource = New Uri(source)
                btnLoad.IsEnabled = InlineAssignHelper(tb.IsEnabled, False)
                txt.Text = "Loading data..."
                txt.Visibility = Visibility.Visible
                maps.Opacity = 0.5
            End If
        End If
    End Sub

    Private Sub Border_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
        Dim bdr As Border = DirectCast(sender, Border)
        Dim wnd As New C1Window() With {
            .ShowMaximizeButton = False,
            .ShowMinimizeButton = False,
            .IsResizable = False
        }
        Dim contImg As New Image() With {
            .MaxWidth = 400,
            .MaxHeight = 400,
            .Stretch = Stretch.None
        }
        wnd.Content = contImg
        wnd.Position(Anchor.Center, Me, Anchor.Center)
        ShowImage(wnd, contImg, bdr, "")
        wnd.ShowModal()

        ' Find other images covered by the current images
        Dim pt0 As Point = e.GetPosition(bdr)

        Dim pt As Point = e.GetPosition(maps)
        Dim pt1 As Point = pt, pt2 As Point = pt
        pt1.X -= pt0.X
        pt1.Y -= pt0.Y
        pt2.X = pt1.X + bdr.ActualWidth
        pt2.Y = pt1.Y + bdr.ActualWidth

        pt1 = maps.ScreenToGeographic(pt1)
        pt2 = maps.ScreenToGeographic(pt2)

        Dim min As New Point(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y))
        Dim max As New Point(Math.Max(pt1.X, pt2.X), Math.Max(pt1.Y, pt2.Y))

        Dim list As New List(Of C1VectorPlacemark)()

        For Each pm As C1VectorPlacemark In vl.Children
            If pm.GeoPoint.X >= min.X AndAlso pm.GeoPoint.X <= max.X AndAlso pm.GeoPoint.Y >= min.Y AndAlso pm.GeoPoint.Y <= max.Y Then
                list.Add(pm)
            End If
        Next

        ' start "slideshow"
        If list.Count > 1 Then
            Dim dp As DispatcherTimer
            Dim tcnt As Integer = 0

            dp = New DispatcherTimer() With {
                .Interval = TimeSpan.FromSeconds(2)
            }
            AddHandler dp.Tick, Sub(se, ea)
                                    tcnt += 1
                                    If tcnt >= list.Count Then
                                        tcnt = 0
                                    End If

                                    ShowImage(wnd, contImg, TryCast(list(tcnt).LabelUI, FrameworkElement), String.Format("{0}/{1} ", tcnt + 1, list.Count))

                                End Sub

            AddHandler wnd.Closing, Sub(s1, e1)
                                        dp.[Stop]()

                                    End Sub

            dp.Start()
        End If
    End Sub

    Private Sub ShowImage(wnd As C1Window, contImg As Image, lbl As FrameworkElement, header As String)
        If lbl IsNot Nothing Then
            Dim im As Image = TryCast(lbl.FindName("img"), Image)
            If im IsNot Nothing Then
                contImg.Source = im.Source
            End If
            Dim tb As TextBlock = TryCast(lbl.FindName("txt"), TextBlock)
            If tb IsNot Nothing Then
                wnd.Header = header + tb.Text
            End If
        End If
    End Sub

    Private _zoom As Double = 0

    Private Sub vl_UriSourceLoaded(sender As Object, e As EventArgs)
        Dim vl As C1VectorLayer = DirectCast(sender, C1VectorLayer)
        Dim bnds As Rect = GetBounds(vl.Children)
        If Not bnds.IsEmpty Then
            maps.TargetCenter = New Point(bnds.Left + 0.5 * bnds.Width, bnds.Top + 0.5 * bnds.Height)

            Dim w As Double = If(maps.ActualWidth > 0, maps.ActualWidth, 500)
            Dim h As Double = If(maps.ActualHeight > 0, maps.ActualHeight, 500)

            Dim scale As Double = Math.Max(bnds.Width / 360 * w, bnds.Height / 180 * h)


            _zoom = Math.Log(512 / Math.Max(scale, 1), 2.0)
            AddHandler maps.CenterChanged, AddressOf maps_CenterChanged
        End If
    End Sub

    Private Function GetBounds(items As IEnumerable(Of C1VectorItemBase)) As Rect
        Dim bounds As Rect = Rect.Empty
        For Each item As C1VectorItemBase In items
            bounds.Union(item.Bounds)
        Next
        Return bounds
    End Function

    Private Sub maps_CenterChanged(sender As Object, e As PropertyChangedEventArgs(Of Point))
        If maps.TargetCenter = maps.Center Then
            RemoveHandler maps.CenterChanged, AddressOf maps_CenterChanged
            maps.TargetZoom = _zoom
        End If
    End Sub

    Private Sub tb_KeyDown(sender As Object, e As KeyEventArgs)
        If e.Key = Key.Enter Then
            Button_Click(btnLoad, New RoutedEventArgs())
        End If
    End Sub
    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
        target = value
        Return value
    End Function
End Class

Public Class ImageConverter
    Implements IValueConverter
    Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
        Dim xe As XElement = TryCast(value, XElement)

        If xe IsNot Nothing Then
            Dim content = xe.Element(xe.GetDefaultNamespace() + "content")
            If content IsNot Nothing Then
                Dim s As String = content.Value
                If Not String.IsNullOrEmpty(s) Then
                    Dim i1 As Integer = s.IndexOf("http://farm")
                    If i1 >= 0 Then
                        Dim i2 As Integer = s.IndexOf(".jpg", i1)
                        If i2 >= 0 Then
                            Return s.Substring(i1, i2 - i1 + ".jpg".Length)
                        End If
                    End If
                End If
            End If
        End If

        Return Nothing
    End Function

    Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Return value
    End Function
End Class
